Linux Shell实用工具
Table of Contents
shell脚本
Shell是一个命令解释器。它不仅是操作系统内核与用户之间的绝缘层,同时也是一种功能相当强大的编程语言。一个Shell程序,通常称为脚本,它是一个由系统调用,命令工具,软件包和已编译的二进制包"粘合" 起来的极易使用的工具。事实上,整个UNIX系统命令,软件包和工具都能由一个shell脚本调用。如果这还不够,Shell的内部命令,比如测试和循环结构,都使Shell脚本更强大和更有弹性。Shell脚本在系统管理任务表现非常的出色,并且对于日常反复性的处理工作避免了使用那些结构过于复杂的程序语言。
分支语句
num=100 if [ $num -lt 60 ] then echo "C" elif [ $num -lt 80 ] && [ $num -ge 60 ] then echo "B" elif [[ $num -lt 90 && $num -ge 80 ]] then echo "A" elif (( $num <= 100 )) && (( $num >= 90 )) then echo "A+" else echo "NA" fi
stage=A case $stage in A) echo "90-100" ;; B) echo "80-90" ;; C) echo "60-80" ;; *) echo "BAD" ;; esac
循环语句
for语句
for x in one two three four do echo number $x done
for x in /var/log/* do echo $(basename $x) is a file living in /var/log done
for j in $(seq 1 5) do echo $j done
for (( i=1; i<=5; i++ )) do echo "i=$i" done
while语句
i=1 while [ $i -le 10 ] do echo $i i=`expr $i + 1`; # let i+=1; # ((i++)); # i=$[$i+1]; # i=$(( $i + 1 )) done
until语句
i=1 until [ $i -gt 10 ] do echo $i i=$(( $i + 1 )) done
文本处理工具
grep
grep -c <pattern> <filename> # 统计出现次数 grep -v <pattern> <filename> # 匹配取反 grep -E <pattern1>|<pattern2> <filename> # or grep -E <pattern1>.*<pattern2> <filename> # and grep -w <pattern> <filename> # 按单词边界查找,非常好用
sed
关于sed的使用,强烈推荐阅读文档:http://www.grymoire.com/Unix/Sed.html。本文是该文档的摘录。另外必须要熟悉sed正则表达式。
sed一般采用/
作为分界符,分界符可以用其它字符,例如要操作的字符串包含/
,那么可以用:
作为分界符来避免引入转义字符。
sed的语法结构为:
sed options 'addr cmd/arg1/arg2/flags' filename
常用选项
-E 扩展正则表达式 -n 只输出匹配的行 -e 脚本表达法,可以执行多条命令 -f 指定脚本名字 -i 就地处理,不产生副本 addr写法
number # match the only number line $ # match last line /regexp/ # match regexp addr1,addr2 # [addr1, addr2] addr1,+N # [addr1, addr1+N]
常用命令
命令 功能 = 打印匹配行号 a\text 将文本插入匹配行之后 i\text 将文本插入匹配行之前 c\text 将匹配行替换为制定文本 d 删除匹配行 p 打印匹配行 s/expr1/expr2/ 将匹配行expr1替换为expr2 y/expr1/expr2/ 将匹配行中expr1中字符替换为expr2中字符,没什么用 常用标志
g 作用于全局 I 忽略大小写 p 打印 w fname 输出到文件
可以用如下的方式来写sed脚本,如果要指定选项,必须将选项放到-f
之前:
#!/bin/sed -nf s/a/A/g s/e/E/g
文本替换
sed 's/src/dst/flags' fname > fname.sed
在sed中,特殊符号&
用于引用匹配字符串,在下面例子中要注意贪婪算法。
1: echo "123 abc" | sed 's/[0-9]*/& &/' # 123 123 abc 2: echo "abc 123" | sed 's/[0-9]*/& &/' # abc 123 3: echo "abc 123" | sed -E 's/[0-9]+/& &/' # abc 123 123
分组表达式是非常重要的特性,每个小括号创建一个分组,用\1
、\2
等引用分组,最多可引用分组为9个。
echo hello123 | sed -E 's/([a-z]*).*/\1/' # hello echo hello world | sed -E 's/([a-z]+) ([a-z]+)/\2 \1/' # world hello echo hello hello world | sed -E 's/([a-z]+) \1/\1/' # hello world
如果只想修改第n次出现,可以用如下表达式:
echo 1b 2b 3b 4b | sed -E 's/b/?/3' # 1b 2b 3? 4b echo 1b 2b 3b 4b | sed -E 's/b/?/3g' # 1b 2b 3? 4?
指定行号范围:
sed -nE '10,20 p' # print line 10-20 sed -nE '10,20 !p' # print line not in 10-20 sed -nE '/^#/ s/[0-9]+//gp' # del num in #line sed -nE '10,/^#/ s/[0-9]+//gp' # del num from 10line to #line sed -nE '10,/^#/ d' # del line from 10line to #line sed -nE '10,/^#/ !d' # del line not in 10line to #line
实用操作
# Windows line to Unix(remove ^M) sed -i 's/\r//' fname # upper to lower sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' fname # grep line begin with cp or scp sed -n '/^s*cp / p' fname sed -n '/^s*cp / =' fname # print line-number only # delete line begin with cp or scp sed -n '/^s*cp / d' fname # del begin whitespace in line sed -i 's/^[ \t]*//g' fname # del trailing whitespace in line sed -i 's/[ \t]*$//g' fname echo world | sed '/world/ i\hello ' # insert before world-line echo world | sed '/world/ a\hello \nend' # append after world-line echo world | sed '/world/ c\hello ' # change line to hello-line ls -lF | sed -nE '/^total\ |.*\/$/ !p' # show file except directory
#!/bin/bash fname=$1 function del_cpp_comment() { # del //... in line begin sed -i '/^[ \t]*\/\// d' $fname # del //... in line end sed -i "s/[ \t]*\/\/[^\"]*$//" $fname # del single line only have /*...*/ sed -i '/^[ \t]*\/\*.*\*\/[ \t]*$/ d' $fname # del single line /*...*/ sed -i 's/[ \t]*\/\*.*\*\///' $fname # del multi line /*...*/ sed -i '/^[ \t]*\/\*/,/.*\*\// d' $fname } del_cpp_comment
awk
参考教程:http://www.grymoire.com/Unix/Awk.html
sed的强项是自动化编辑文本,awk的强项是分析数据生成报告。相比于sed,awk更像是一门语言,和C语言有很相似的语法结构。
awk的默认工作流程是读取每一条记录,按照空格分解为子项目,用$1
、$2
这样的方式引用子项,注意$0
表示所有子项。可以用-F ':'
这样的选项将默认的空格分隔符改变为使用冒号作为分隔符。
awk有许多内置变量,并且可以被修改:
ARGC | 命令行参数个数 |
ARGV | 命令行参数排列 |
ENVIRON | 支持队列中系统环境变量的使用 |
FILENAME | awk浏览的文件名 |
FNR | 浏览文件的记录数 |
FS | 设置输入域分隔符,等价于命令行-F选项 |
NF | 浏览记录的域的个数 |
NR | 已读的记录数 |
OFS | 输出域分隔符 |
ORS | 输出记录分隔符 |
RS | 控制记录分隔符 |
ls -l | awk '{print $3,$9}' cat /etc/passwd | awk -F ':' 'BEGIN {print "name\tshell"}{print $1"\t"$7}' awk -F ':' '{printf("file:%10s %s %s: %s\n",FILENAME,NR,NF,$0)}' /etc/passwd
系统工具
系统性能分析
top
该指令的命令行格式为:
top -hv|-bcHiOSs -d secs -n max -u|U user -p pid -o fld -w [cols]
h/v | 帮助/版本信息 |
b | 批量模式 |
d | 延迟时间:如0.1表示0.1s |
H | 线程单独显示,而不是依附到进程内部 |
i | 不显示空闲进程 |
n | 刷新指定帧数之后退出 |
o | 用于更改排序优先级,+降低,-增加 |
p | 指定观察进程 |
top - 09:38:06 up 4 days, 16:58, 7 users, load average: 0.72, 0.23, 0.19 Tasks: 251 total, 3 running, 248 sleeping, 0 stopped, 0 zombie %Cpu(s): 26.7 us, 2.2 sy, 44.1 ni, 1.5 id, 25.3 wa, 0.0 hi, 0.2 si, 0.0 st KiB Mem: 5998076 total, 5797400 used, 200676 free, 127412 buffers KiB Swap: 7916540 total, 28824 used, 7887716 free. 3143600 cached Mem
- user/us
- 用户进程使用占比
- sys/sy
- 内核进程使用占比
- nic/ni
- nice用户进程使用占比
- idle/id
- 空闲时间占比,如果这个值过低,表示CPU存在瓶颈
- io/wa
- 等待IO的占比,如果这个值过高,表示IO存在瓶颈
- irq/hi
- 中断占比
- sirq/si
- 软中断占比
- steal/st
- 虚拟CPU使用占比,一般在虚拟机中才能看到
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1286 root 20 0 362848 63316 32652 S 1.0 1.1 34:57.79 Xorg 1855 micky 20 0 1136568 84168 24656 S 1.0 1.4 49:49.06 compiz 23997 micky 20 0 556880 94936 18764 S 0.7 1.6 0:26.23 emacs 54 root 20 0 0 0 0 S 0.3 0.0 0:38.91 kworker/1:1 23969 micky 20 0 593700 23772 13896 S 0.3 0.4 0:02.94 gnome-terminal 24492 micky 20 0 29168 1768 1184 R 0.3 0.0 0:00.03 top
- PID
- 进程ID
- USER
- effective USER名
- PR
- 优先级
- NI
- nice值
- VIRT
- 虚拟内存大小
- RES
- 驻留内存大小,即使用的不可交换物理内存
- SHR
- 共享内存大小
- %CPU
- CPU占用率
- %MEM
- MEM占用率
- TIME
- 已执行时间
- COMMAND
- 命令行
此外top命令还有很多交互式命令,如下所示:
4a. Global-Commands <Ent/Sp> ?, =, 0, A, B, d, E, e, g, h, H, I, k, q, r, s, W, X, Y, Z 4b. Summary-Area-Commands C, l, t, m, 1, 2, 3 4c. Task-Area-Commands Appearance: b, J, j, x, y, z Content: c, f, F, o, O, S, u, U, V Size: #, i, n Sorting: <, >, f, F, R 4d. Color-Mapping <Ret>, a, B, b, H, M, q, S, T, w, z, 0 - 7 5b. Commands-for-Windows -, _, =, +, A, a, g, G, w 5c. Scrolling-a-Window C, Up, Dn, Left, Right, PgUp, PgDn, Home, End 5d. Searching-in-a-Window L, &
这里介绍几个实用的命令:
- M
- 进程列表按内存使用大小降序排序
- P
- 进程列表按CPU使用大小降序排序
free
free命令的数据都是从/proc/meminfo
中读取的。
$ free total used free shared buffers cached Mem: 5998076 5771648 226428 437208 372552 3365820 -/+ buffers/cache: 2033276 3964800 Swap: 7916540 263972 7652568
- Mem
- 从操作系统来看,显示的是物理内存,
buffers表示要写入到磁盘的数据,cached表示从磁盘缓存的数据,可以用
echo 3 > /proc/sys/vm/drop_caches
清除缓存
vmstat
用于统计虚拟内存信息:
vmstat [options] [delay [count]]
a | 显示active/inactive内存 |
f | 显示总forks数目 |
m | 显示slabinfo |
n | 只显示header一次,而不是周期性刷新 |
s | 以表格形式显示各事件统计信息 |
d | 磁盘统计信息 |
D | 磁盘统计信息概要 |
p partition | 分区统计信息 |
S unit | 指定单位,k/K,m/M |
mpstat
mpstat [-A] [-u] [-V] [-I {SUM|CPU|SCPU|ALL}] [-P {cpu [,...]|ON|ALL}] [interval[count]]
- -A
- 等价于
-u -I ALL -P ALL
- -I {SUM|CPU|SCPU|ALL}
- 中断统计信息
- -P {cpu [,…]|ON|ALL}
- 指定要报告的CPU
其它工具
find
find命令可以用-type
指定文件类型:
b | Block special file |
c | Character special file |
d | Directory |
f | Plain file |
p | Named Pipe File |
l | Symbolic link |
s | Socket |
可以用-size
指定文件大小:
27 | 固定大小 |
+10000c | 大于10000字节 |
-10000c | 小于10000字节 |
可以用-mtime
指定修改时间,用-atime
指定访问时间:
7 | 7天前修改 |
+7 | 7天之前修改 |
-7 | 7天以内修改 |
可以用-perm
指定文件权限:
664 | 文件访问权限为664 |
-020 | 对020取按位与操作,不为0即所查找 |
另外可以用-user
和-group
用户和组,后面可以是名字也可以是编号。
find . -print # print all files in curdir ls -ld `find . -print` # print all files long list find . -name "*.c" -o -name "*.cpp" # find c/c++ files
正确含有空格的文件名
ref: How do I use find when the filename contains spaces?
一种方法是使用-print0
选项:
find . -type f -print0 | xargs -0 echo find . -type f -print0 | xargs -0 -n 1 echo
另一种方式是使用-exec
选项:
find . -type f -exec echo '{}' + find . -type f -exec echo '{}' \;
远程登录
ssh
如果登录出现如下警告,需要更新known_hosts
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is also possible that a host key has just been changed. The fingerprint for the RSA key sent by the remote host is 6e:45:f9:a8:af:38:3d:a1:a5:c7:76:1d:02:f8:77:00. Please contact your system administrator. Add correct host key in /home/XX/.ssh/known_hosts to get rid of this message. Offending RSA key in /var/lib/sss/pubconf/known_hosts:4 RSA host key for pong has changed and you have requested strict checking. Host key verification failed.
ssh-keygen -R hostname ssh-keygen -R [23.34.56.76]:26 # 指定端口的格式
可以利用配置/etc/ssh/ssh_config
设置ssh行为。
StrictHostKeyChecking no # 避免询问加入known_host