目录

Shell 文本处理

  1. find 查找出需要处理的所有文件

  2. cat 将所有文件拼接,成为起始的stdin

  3. grepstdin流里过滤出,自己想要的行

  4. sedstdin流进行 字符串替换,tr 对流进行单个字符式的替换、去重、删除

  5. cutstdin中每一行,切出指定列,awk 也是切出指定多个列,还是可编程命令

  6. sort对所有行排序,排序好后,可以用uniq -c去除相同的行,再sort -nr到序输出

  7. wc -l统计下行数,或者sed '100,$d' 只取前 100 行

$ find . -name "*.php" | xargs cat | grep | [sed |tr] | [cut|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 -nr "size" ./                          #    递归搜索当前目录下的所有文件 ,过滤出含有 `size` 的行,并显示它们的行数
grep -E '219|216' data.doc      # 匹配带有 219 或者 216的行, | 语法是 ERE 里才有的

sed 字符串替换

sed 's/test/mytest/g' a.txt             # test => mytest, 每行替换多个
sed 's/^192.168.0.1/& localhost/' a.txt # &是引用前一个字符串,表示将替换为 192.168.0.1 localhost
sed 's/\(love\)able/\1rs/p' a.txt    # love 被标记为 1,所有 loveable 会被替换成 lovers

tr 单个字符替换 去重 删除

tr [options] set1 set2 只从 stdin 中读取输入,输出到stdout

# 连续重复的 多个字符 只保留 1 个
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

cut 切下每一行里指定列的数据

cat /etc/passwd | cut -d: -f 7 # 以 : 为分割符 切出第 7 列

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

  • 下列命令,teecat的 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