linux开发常用脚本,记录自己常用的一些 Linux Shell 脚本

常要在 Linux 下分析日志或其他类型的文件,基本用的命令也就 grep, awk, sed, cut, vim, cat, find, xargs, tail, more 或 less。本人工作平台为 Mac OS X, 而 Mac 下的 grep, sed, awk 的行为与 Linux 下的 GNU 标准的相应命令是有差别的, 所以我总是在 Mac 下安装 GNU 的 grep, sed, awk 等命令来替代系统默认的。

比如安装下面的命令

$ brew install findutils gawk gnu-sed grep

以上会安装 GNU 的 find, awk, sed 和 grep 命令,使用时要加个前缀,如 gfind, gawk, gsed 或 ggrep,也可以设置别名或符号链接来替换掉系统的相应命令。

注: brew install coreutils 会安装众多 Linux 下的基本命令替代品,ls, cat, cut 都在其中,使用它也是要加上前缀 g, 如 gls, gcut 等。

以下 grep, find, grep, sed 以 GNU 的行为为准。

grep 相关的命令

用了这么久的 grep, 反正它是用来查找字符串的,还能用正则表达式匹配。那么它的全名是什么呢?Global Regular Expression Print (GREP)。

高亮显示匹配的字符串

这个效果很重要,不然显示出了字符串还不清楚哪里匹配了,所以最好用个 alias

grep="grep --color=auto --exclude-dir={.bzr,CVS,.git,.hg,.svn}"

2e96047e47227e2516088d0543e52de5.png

以下各种使用方式

$ cat planets.txt | grep -i e      # 忽略大小写匹配

$ cat planets.txt | grep -e "[p|P]"  # 使用正则表达式匹配

$ cat planets.txt | grep -P -e "[p|P]{1,3}"  # 使用 Perl 风格正则表达式

搜索文件

$ grep -r --include "*.java" "print" src   # 从 src 目录中的 *.java 中递归查找 print 字符串

输出捕获的分组

打印出匹配的字符串并不需总是要用 awk 分隔再打印,用 grep -oP 或 egrep -o 会更方便,如

$ echo 'employee_id=1234' | egrep -o '\d+'

1234

$ echo 'employee_id=1234' | grep -oP 'employee_id=\K(\d+)'                       # Mac OS X 下可用   ggrep, P 为 Perl 正则表达式, \K 是 Perl 用来实现 look-behind, 如从 "=" 开始

1234

$ echo 'employee_id=1234' | grep -oP '(?<==)(\d+)'                                       # 另一种 lookbehind 方式, '(?<==)' 中的 ?<= 指定从后它后的的 = 号开始

1234

$ echo 'foo something bar' | grep -oP '(?<=foo )\w+(?= bar)'                        # 用这个了理解一下 grep -P  Perl 的 look-behind 和 look-ahead

something

其他几种输出分组的方式

$ echo 'employee_id=1234' | sed 's/^.*employee_id=\([0-9]*\).*$/\1/'

1234

$ echo employee_id=1234 | sed -E 's/employee_id=([0-9]+)/\1/g'                 # -E extended regex

1234

$ echo 'employee_id=1234' | awk -F= '{print $2}'

1234

$ foo='employee_id=1234'                                                                                        # 以下是 bash 的方式

$ echo ${foo%%=*}

employee_id

$ echo ${foo#*=}

1234

控制台的内容直接送到 vim 编辑器中

未打开 vim, 可用管道操作 xxx | vi - 如:

$ ls -l | grep py | vi -      # 这样会打开 vim 编辑器,显示 ls -l |grep py 命令的输出内容

如果打开了 vim, 那么在 vim 中命令模式中输入

: read !ls -l | grep py     # 就会在当前 vim 编辑器中添加 ls -l | grep py 命令的输出内容

打开 vim 的同时打开语法高亮, 如果 ~/.vimrc 中已打开语法高亮,但 | vi - 没有告知文件类型,所以需要 vim 启动时加上 set syntax=json 或 set filetype=json

$ echo '{"age": 28}' | vi - -c 'set syn=json'      # 或者 set syntax=json, set filetype=json 或 set ft=json

$ echo '{"age": 18}' | vi -

也可以进入了 vim 后,在它的命令行下设置  :set syntax=json 或  :set filetype=json, 或简单的用 :set syn=json 或 :set ft=json。

另外,假如用 vim 打开一个大文件,因为加载过多插件的因素滚动慢,可以用 vi -u NONE bigfile.json 来打开文件。

切分字符串

这也用到的命令就是 cut 或 awk,cut 能力比较弱,只能用单字符切割字符串,看如下几个使用方式

$ echo "aa,bb,,cc:dd" | cut -d, -f1

aa                                                               # -d 后指定用 , 号分隔,-f 输出哪个字段

$ echo "aa,bb,,cc:dd" | cut -d, -f1 -f4   # 或者用 -f1,4

aa,cc:dd                                                    # 输出多个字段时又会用 -d 指定的分隔符连接

$ echo "aa,bb,,cc:dd" | cut -d, -f4 | cut -d: -f1

cc                                                                #由于不支持模式分隔,所以要进行两次切分

另一种方法就是用 awk 命令,awk 简单是一个编程语言,它名字来源于它的三位作者的名字首字母(Aho, Weinberger and Kernighan), 不是 awkward 的意思。它的功能还是很强,我们且在这里看看怎么分隔字符串

$ echo "aa,bb,,cc:dd" | awk -F "(,*)|:" '{print NF,$1,$2,$3,$4}'

4 aa bb cc dd       # 共四个字符,且每个字段的内容,-F 中支持正则表达式

实际使用时应测试好它所支持的正则表达式的语法,以前好像还尝试过 awk 的正则表达式的切割功能,还以为需要用 Python 的实现类似的操作。

曾经想过用 Python 的切分字符串的方式 (cut.py)

#!/usr/bin/env python

import sys

from optparse import OptionParser

import re

parser = OptionParser()

parser.add_option('-d', '--delimiter', default='\t')

parser.add_option('-f', '--fields')

(options, args) = parser.parse_args()

indexes = [(int(i) - 1) for i in options.fields.split(',')]

regex = re.compile(options.delimiter)

for line in sys.stdin:

fields = regex.split(line.rstrip())

out = ' '.join([fields[i] for i in indexes])

print(out)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#!/usr/bin/env python

importsys

fromoptparseimportOptionParser

importre

parser=OptionParser()

parser.add_option('-d','--delimiter',default='\t')

parser.add_option('-f','--fields')

(options,args)=parser.parse_args()

indexes=[(int(i)-1)foriinoptions.fields.split(',')]

regex=re.compile(options.delimiter)

forlineinsys.stdin:

fields=regex.split(line.rstrip())

out=' '.join([fields[i]foriinindexes])

print(out)

然后执行

$ echo "aa,bb,,cc:dd" | cut.py -d",+|:" -f1,2,4    # Python 的正则表达式也需多测试

aa bb dd

输出匹配后的下一行

通常我们的需求是用  grep 查找到并输出匹配行,有时我们想输出匹配行的下一行,或下几行,比如说对 ini 文件

[memory]

max=8G

[bandwidth]

max=4G

我们想要找到含有 [memory] 的下一行的 max 值而不是别处的 max

可以用  awk 命令

cat test.ini | awk '/\[memory\]/{getline;print}'   #\[ 为转义 [ 符号

max=8G

或者用 sed 命令(sed 是什么?Stream EDitor, 流编程器,也可说是像 awk 一样另成一种编程语言

cat test.ini | sed -n '/[memory]/{n;p;}'   # 很像 awk 的  getline;print

max=8G

sed 中的命令非常精简,都用单字母,如 a: append, s: substitue, n: next, p: print。如果要用来处理字符串替换的操作 sed 就是最好的编程工具。

grep 本身也能完成类似的功能

$ cat test.ini | grep -A1 '\[memory\]'    # 往下多显示一行  -A, --after-context=NUM 从当前往下多少行,往前是 -B

[memory]

max=8G

前面说过 awk  本身就是个编程语言的,所以还能加入更多代码

$ cat test.ini | awk '/\[memory\]/{for(i=0;i<4;i++)getline;print $0}'

max=4G

//或者

$ cat test.ini | awk -v lines=4 '/\[memory\]/{for(i=lines;i;--i) getline; print $0}'

max=4G

awk 和 sed 是可以直接读取文件的,所以前面的命令可以不用 cat test.ini 到它的管道操作,而可以

$ awk '/\[memory\]/{for(i=0;i<4;i++)getline;print $0}' test.ini

$ sed -n '/[memory]/{n;p;}' test.ini

sort 命令按某列排序

sort 命令可以帮我们对文本行排序,默认以整行字符串为比较单位,主要参数有

-n:  --numberic-sort, 比较数字大小而非字符串来排序

-r:--reverse, 逆序排列

-f: --ignore-case, 忽略大小写排序

这儿我们了解另一种排序需求,即按文件中某一列进行排序,如果有如下文件 planets.txt, 内容为

Moon,3

Sun,1

Earth,2

1

2

3

Moon,3

Sun,1

Earth,2

我们想要按第二列进行序列后输出全部内容,那么命令为

$ sort -t, -k2 planets.txt

Sun,1

Earth,2

Moon,3

解析:

-t: --field-separator, 以逗号为分割符, 默认是以空格分割

-k2: --key, 先取第二列为排序依据

除此之外,sort 还有以下两个有意思的功能

-R: --random-sort, 随机打乱顺序

-u: --unique, 去重功能,从此告别 sort | uniq 这样的管道操作

看一下 -u 去重的功能,修改 planets.txt 内容如下

Moon,3

Sun,1

Earth,2

XXX,1

1

2

3

4

Moon,3

Sun,1

Earth,2

XXX,1

$ sort -t, -k2 -u planets.txt

Sun,1

Earth,2

Moon,3

在用 -t, -k2 时还是按照重复列来去重的。

批处理利器 xargs 命令

提起 xargs 命令时让人不禁想起 find 这一绝配,通常是 find 找到某些符合条件的文件后用管道传递给  xargs  去批量操作,有时也会 find -exec 命令来操作。比如

$ find . -type f -size +800M -exec rm {} \;                         //或

$ find . -type f -size +800M -exec rm {} +

除此之外也会用到 xargs 命令与 find 配合

$ find . | xargs -0 rm -f

$ find . -type f | xargs -I {} cp {} /var/www

上面第一个命令,找到的内容是放到 rm -f 后面,可以不用 {} 的形式;  如果不加 -0 (数字零)参数,rm 删除太多文件时会出现 Argument list too long 的错误。第二个命令因为内容放在 cp 命令中间,所以要用 {} 点位符; 同样的,如果操作的文件太多,在 xargs  命令中也要加上  -0 参数。

除此之外,xargs  还能把单行转成多行

$ cat <

> a b c d

> e f

> g

> EOF

a b c d e f g

更多功能见文后的链接。

链接:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值