grep
用于文本搜索,匹配文件内容,语法格式为:grep pattern filename,例如:

# 找出所有含有for的行grep 'for' test.sh# 对多个文件进行搜索grep 'for' test.sh bak.sh# 高亮匹配部分grep 'for' test.sh --color=auto

默认是通配符匹配,正则表达式需要开启参数E(extended):

# 找出所有以echo开头的行grep -E '^\s*echo' test.sh

或者使用默认允许正则表达式的egrep命令:

# 同上egrep '^\s*echo' test.sh

其它选项及特性:

# 只输出匹配部分grep -o -E '\s[a-zA-Z]\s' test.sh# 只输出不匹配的行(反选)grep -v -E '\s[a-zA-Z]\s' test.sh# 统计匹配行数grep -c -E '\s[a-zA-Z]\s' test.sh# 统计匹配项数grep -o -E '\s[a-zA-Z]\s' test.sh | wc -l# 输出匹配行及其行号grep -n -E '\s[a-zA-Z]\s' test.sh# 输出匹配项所在的文件名(反选是L)grep -l 'return' test.sh bak.sh return.sh# 递归搜索目录,输出文件名及行号grep -n -R  'echo' .# 忽略大小写grep -i "ECho" test.sh# 目录搜索限定文件名格式# 注意include参数的值必须用引号包起来,与find命令不同grep -R '=>' . --include '*.jsx}'# 目录搜索排除特定格式文件名、目录grep -R '' . --exclude '*.md' --exclude-dir 'node_modules'# 输出\0作为终结符,一般配合-l只输出文件名,再xargs -0传递给后续命令grep "echo" . -R -l -Z | xargs ls -l# 静默匹配,不向stdin输出任何东西,匹配成功返回0if echo ' abcd' | grep -q -E '^\s*abc'; then echo 'starts with abc'; fi

除了定位匹配项,还可以输出匹配项的上下文:

# 输出匹配行及后续2行seq 10 | grep '4' -A 2# 输出匹配行及之前2行seq 10 | grep '4' -B 2# 输出匹配行及前后各2行seq 10 | grep '4' -C 2

cut
有3种切分方式:-c按字符切分,-f按字段切分,-b按字节切分

按字符切分:

# 切出每行第3个字符到第5个字符echo $'1 2 3 4\n5 6 7 8' | cut -c 3-5# 第3个字符到行尾echo $'1 2 3 4\n5 6 7 8' | cut -c 3-# 第5个字符及之前echo $'1 2 3 4\n5 6 7 8' | cut -c -5

按字段(列)切分,把一列当做一个字段,类似于awk,提取指定的列:

echo $'1 2 3 4\n5 6 7 8' | cut -d ' ' -f 1,3

注意:一个非常重要的问题是分界符,默认是制表符(Ctrl + v再tab),-d选项指定其它字符,只能是单字符,不好用(无法应对多空格的情况,只适用于单字符分隔的内容)

例如切出ps结果中的PID和CMD列:

# awk完美解决问题ps | awk '{print $1,$4}'# cut不好用# 默认按制表符cut无效ps | cut -f 1,4# 指定空格cut结果不对ps | cut -d ' ' -f 1,4

按字节切分,默认会忽略多字节字符边界:

# 默认跨字符切分,汉字被切坏了echo "想做个好人" | cut -b 2-4# -n选项不分割多字节字符,得到`想`echo "想做个好人" | cut -n -b 2-4

sed
stream editor,非交互式的编辑器,常用的文本处理工具,最常用的功能是文本替换:

# 删除行开头的空白字符echo $' \t  我想左对齐' | sed  $'s/^[[:space:]]*\t*//g'

另一个常用功能是文件原地替换(替换并把结果写入原文件):

# 把test.txt里所有的单词替换为[word]echo $'this is a new file\nnext line' > test.txtsed -i '' -E 's/[[:alpha:]]{1,}/[word]/g' test.txt

P.S.Mac下sed -i文件原地替换必须指定备份文件名(虽然可以是空串),另外,Mac下的sed与GUN sed差异非常大,比如没有+、?,没有\b等等,更多差异请查看Differences between sed on Mac OSX and other “standard” sed?

一般定界符是/,也可以是任意符号:

# 分号echo $'\t\t\t我想左对齐' | sed $'s;^\t*;;'# Mac下甚至可以是`|`echo $'\t\t\t我想左对齐' | sed $'s|^\t*||'# 没有分界含义的定界符需要转义echo '&c' | sed -E 's;&[[:alpha:]]{1,}\;;\&;'

其它常用选项:

# /pattern/d删除匹配的行sed '/^$/d' test.sh# &表示本次匹配部分echo 'abc de' | sed -E 's/[[:alpha:]]{1,}/[&]/g'# \123..反向引用echo 'aabcc' | sed 's/\([[:alpha:]]\)\1/[\1x2]/g'# sed 'expr1; expr2...'顺序应用多个正则,效果等价于管道echo 'aabcc' | sed 's/\([[:alpha:]]\)\1/[\1x2]/g;s/\].*\[/][/'

注意:反向引用例子中的捕获括号必须转义

awk
通常被用于按列提取,例如:

# 文件名ps | awk '{print $1, $4}'

非常强大,可以对列和行进行操作,一般格式如下:

awk 'BEGIN{ print "start" } pattern1{ command } END{ print "end" }' fileBEGIN、END和模式块都是可选的,先执行BEGIN块,然后从输入内容中读取一行,依次执行各个模式块,直到所有内容读取完毕,然后执行END块

pattern也是可选的,不提供表示对每行无条件执行块中的语句,例如:

# 原样输出echo $'1 2\n3 4' | awk '{print}'# 统计行数echo $'1 2\n3 4' | awk 'BEGIN{lineCount=0} {let lineCount++} END{print lineCount}'

print比较特殊,空格分隔的参数输出时会被连接起来,逗号分隔参数输出时会用空格分隔开,例如:

# 输出123echo '' | awk '{print 1 2 3}'# 输出1 2 3echo '' | awk '{print 1,2,3}'# 输出1-2-3echo '' | awk '{print 1"-"2"-"3}'

内置变量
awk里有一些特殊的内置变量:

NR:number of records,当前行号NF:number of fields,当前行字段数$0:当前行文本内容$123…:当前行第n个字段的文本内容

所以有更简单的统计行数的方式:

echo $'1 2\n3 4' | awk 'END{print NR}'
每读一行更新NR,执行到END块时就是总行数

注意:awk里取变量值不需要通过$取值,无论是内置变量还是自定义变量

传递外部变量
awk里不能直接使用外部变量,需要传递进来:

# 输出空x=3; echo '' | awk '{print x}'# 输出3x=3; echo '' | awk -v x=$x '{print x}'

传递多个外部变量有更简单的方式:

# 输出3 4 5x=3; y=4; z=5; echo '' | awk -v x=$x -v y=$y -v z=$z '{print x,y,z}'# 简单方式x=3; y=4; z=5; echo '' | awk '{print x,y,z}' x=$x y=$y z=$z

以键值对方式紧跟在语句块后面,作为命令行参数传入

getline

一般用来读取下一行,用法如下:

# 输出第一行echo $'1 2\n3 4' | awk 'BEGIN{getline line; print line}'# 跳过第一行(把第一行的total xxx丢弃了)ls -l | awk 'BEGIN{getline} {print $0}'

不带参数的getline会更新$0123...(带参数的不会),例如:

# 带参数的不更新字段变量echo $'1 2\n3 4' | awk 'BEGIN{print $0; getline line; print $0}'# 不带参数的会更新字段变量echo $'1 2\n3 4' | awk 'BEGIN{print $0; getline; print $0}'

执行其它命令
在awk中执行其它命令也比较特殊:

# $0是md5 test.sh的输出结果echo '' | awk '{"md5 test.sh" | getline; print $0}'# 或者echo '' | awk '{"md5 test.sh" | getline md5; print md5}'

循环、条件
在awk中可以使用C语言风格的循环、条件等结构:

# while循环seq 10 | awk 'BEGIN{while (getline){print $0}}'# for循环seq 10 | awk 'BEGIN{for(i=0; i<10; i++){getline; print $0}}'# 条件语句seq 10 | awk 'BEGIN{for(i=0; i<10; i++){getline; if ($1 % 2) {print $0}}}'

这些特性让awk变得很强大,逐行处理文件非常便捷

P.S.更多语句结构,及内置函数请查看man awk

其它选项
常用的选项:

# 指定定界符,默认是空格echo 'a;b;c' | awk -F ';' '{print $2}'# 或者echo 'a;b;c' | awk 'BEGIN{FS=";"} {print $2}'# 指定输出定界符echo 'a b c' | awk 'BEGIN{OFS="\t"} {print $1,$2,$3}'# 模式过滤# 行号小于2echo $'1 2\n3 4' | awk 'NR < 2{print $0}'# 行号在2到4之间seq 10 | awk 'NR==2,NR==4{print $0}'# 匹配正则表达式echo $'1 2\n3 4' | awk '/^3/{print $0}'

处理文件内容
逐行读取:

# 输入重定向while read line; do echo $line; done < test.sh# 或者子shellcat test.sh | (while read line; do echo $line; done)

读取一行中的各个字段:

line='1 2 3 4'; IFS=' '; for field in $line; do echo $field; done

读取一个字段中的每个字符:

field='word'; for ((i=0;i<${#field};i++)) do echo ${field:i:1}; done

这里用到一个子串截取的技巧${field:i:1},格式为${var:start_index:length},起点可以是负数,表示倒数:

# 截取最后2个字符field='abcdef'; echo ${field:(-2):2}

P.S.shell的这些字符串处理支持确实强大到没朋友

paste
按列拼接文本内容,cat按行拼接,paste可以按列拼接:

seq 3 > no.txtecho $'吃饭\n睡觉\n打豆豆' > action.txt# 按行拼接cat no.txt action.txt# 按列拼接paste no.txt action.txt

paste结果如下:

# paste no.txt action.txt | sed -n l1\t吃饭$2\t睡觉$3\t打豆豆$

默认定界符用制表符,可以用-d选项指定其它定界符:

# 拼接结果用分号分隔paste -d ';' no.txt action.txt | sed -n l

更多相关文章

  1. Java 中字符集的编解码
  2. 008. 字符串转换整数 (atoi) | Leetcode题解
  3. 003. 无重复字符的最长子串 | Leetcode题解
  4. Jquery对选取到的元素显示指定的长度,对于的字符串用“...”显示
  5. 将字符串数组发布到.net-core mvc
  6. js或Jquery中判断字符串中是否有换行符或回车符/n
  7. 通过],[和创建json对象来分割字符串
  8. jQuery返回一个没有逗号的字符串的前5个单词
  9. 将Object转换为字符串并返回[复制]

随机推荐

  1. Android长按弹出菜单
  2. Android 博客园客户端 (二) 新界面&部分功
  3. Android使adb作为host运行在arm64平台
  4. Android Eclipse JNI 调用 .so文件加载
  5. [Android L]关于Android L的Service启动
  6. android 编译源码 错误解决2
  7. Android 签名类型
  8. Google Maps Android API V2 版本更新导
  9. Android ListView优化
  10. android ui 布局性能优化