Shell文本处理
find
查找出需要处理的所有文件cat
将所有文件拼接,成为起始的stdin
grep
从stdin
流里过滤出,自己想要的行sed
对stdin
流进行 字符串替换,tr
对流进行单个字符式的替换、去重、删除cut
对stdin
中每一行,切出指定列,awk
也是切出指定多个列,还是可编程命令sort
对所有行排序,排序好后,可以用uniq -c
去除相同的行,再sort -nr
到序输出wc -l
统计下行数,或者sed '100,$d'
只取前 100 行
$ find . -name "*.php" | xargs cat | grep | [sed |tr] | awk | [sort|uniq] | wc -l
cat
cat file1 file2 file3 # 拼接输出多个文件
echo 'text through stdin' | cat - file.txt # 将输入stdin和file.txt拼接起来, - 是stdin文本的文件名
grep
格式: grep [options] "正则" [files ...]
读取命令行上每个文件,输出匹配到查找模式的行
-i 忽略大小写
-v 反转 没匹配到的行
-h 查询多文件时不显示文件名
-l 只打印匹配到内容的文件的名字,而不是匹配的每一行
-r 表示输入的路径是一个目录,匹配目录下的所有文件
-n 输出匹配处在文件内的行数
grep "size" file.txt # 在file.txt中找包含size的行 (使用正则表达式匹配)
grep -inr "size" ./ # 递归搜索当前目录下的所有文件 ,过滤出含有 `size` 的行,并显示它们的行数
grep -E '219|216' data.doc # 匹配带有 219 或者 216的行, | 语法是 ERE 里才有的
awk
$0 整条记录
$1 第1列
$2 第2列 ... 以此类推
// 显示 /etc/passwd 的账户
$ cat /etc/passwd | awk -F: '{print $1}' # 按照 : 将一行分割成多列,-F 是制定分割符,默认是空格和制表符
// 删除用户zdd的所有文件,注意-rf后面有一个空格
$ ls -l | grep zdd | awk '{print "rm -rf " $9}' | sh
sed 字符串替换
sed 's/test/mytest/g' a.txt # test => mytest, 每行替换多个
tr 字符替换 去重 删除
tr [options] set1 set2
只从 stdin
中读取输入,输出到stdout
。
# 去重
cat file.txt | tr -s ["\n"] # 删除多余的空白行
echo 'GNU is not UNIX' | tr -s ' ' # 删除多余的空格 GNU is not UNIX
# 删除
echo "its 10:00 Now" | tr -d "[0-9][:]" # 删除数字和冒号 its Now
# 替换
echo 12345 | tr '0-9' 'abcdefghij' # 一一对应式的替换 abcde
echo "Hello world i love you " | tr [a-z] [A-Z] # 小写换成大写 HELLO WORLD I LOVE YOU
join 链接字段
格式 join [option] file1 file2
以同一个键值,将两个文件内的同键的行合并为一条
# sales.txt
joe 100
jane 200
# quotas.txt
joe 50
jane 100
$ join sales.txt quotas.txt
# 合并后
joe 100 50
jane 200 100
sort 排序
sort [option] [files ...]
-b 忽略开头空白
-t 设定分割符(默认空白),将一行字符串分割
-k 指定按某个分割的列排序
-n 按数值大小比较,而不是 ascii 字符串
-r 顺序反转,从大到小排序
uniq 去重复行
uniq uniq.txt # 去重 连续两条一样的行 即为重复,只保留一条
uniq -u uniq.txt # 只显示唯一的行
uniq -d uniq.txt # 找出重复的行
uniq -c uniq.txt # 统计出现行数
wc 统计行数,字数,字符数
-l 只输出行数
-w 只输出字数
-c 只输出字节数
$ wc /etc/passwd
45 76 2528 /etc/passwd
tee 将 stdin 复制一份
它只能复制上一个命令的 stdout,而忽视 stderr,除非
2>&1
下列命令,
tee
将cat
的 stdout 输出复制到 out.txt,同时cat
的 stdout 和 stderr 的输出都传给了下一个管道-a
选项是追加,不加的话,每次会覆盖文件的值
cat a* | tee -a out.txt | cat -n
comm 比较两个文件
$ comm A.txt B.txt # 第1列为A文件独有 第二列为B文件独有 第三列为两者相同的行
apple
carrot
cookies
gold
iron
orange
silver
steel
$ comm A.txt B.txt -1 -2# 不输出第1列,第2列
gold
orange
$ comm A.txt B.txt | sed 's/^\t*//' # 并集
$ comm A.txt B.txt -1 -2 | sed 's/^\t*//' # 交集
$ comm A.txt B.txt -1 -3 | sed 's/^\t*//' # B - A
$ comm A.txt B.txt -2 -3 | sed 's/^\t*//' # A - B
批量改名
name=${basename $0} # 从路径里面获取脚本名称
file="a.txt.jpg"
name=${file%%.*} # 获取文件名
ext=${file##*.} # 获取后缀名
#!/bin/bash
oldsuffix="cpp"
newsuffix="cc"
dir=$(eval pwd)
for file in $(find | grep .${oldsuffix} ) ;do
name=`echo $file | sed 's/.cpp$//g'`
echo "cp" ${file} ${name}.${newsuffix}
cp $file ${name}.${newsuffix}
done