常用运维shell脚本

444 阅读9分钟

前置文章

《Linux之shell编程》
《Linux命令汇总》
《2万字系统总结,带你实现 Linux 命令自由?》
《学习如何编写 Shell 脚本(基础篇)》
《学习如何编写 Shell 脚本(进阶篇)》

几个常用Linux命令总结

xargs

我们都知道,在Linux中,管道|命令可以实现将左侧命令的标准输出转换为标准输入提供给右侧命令使用,但是有些命令不接受管道的传递方式,例如lsecho等,其实有很多命令都不支持标准输入作为参数,只能在执行命令行时指定参数,这就导致不能使用管道|命令传递参数。而xargs命令的功能就是将标准输入进行处理,然后转化为命令行参数。

语法格式

command | xargs [options] command

常用参数如下:

  • -a file:从文件中读入作为标准输入stdin
  • -d:默认情况下,xargs将换行符和空格作为分隔符,-d可以更改分隔符
  • -p:打印要执行的命令,询问用户是否要执行
  • -t:打印要执行的命令,然后直接执行,不需要用户确认

使用实例

上面说到,有很多命令都不支持标准输入作为参数,导致不能使用管道|命令传递参数,但是,xargs和管道一起使用时,就可以了。

例如:

find 命令接受管道传递参数
find | grep test
# cat 命令不接受管道传递参数
cat test.txt
# hello xargs!
echo "test.txt" | cat
# test.txt
[root@centos7 test]#
# xargs 将标准输入转为命令行参数
echo "test.txt" | xargs cat
# hello xargs!

可以看到,cat命令不接受管道传递参数,我们尝试通过标准输入把参数传给cat, 结果只是显示了文件名 ,xargsecho的输出作为标准输入传递给了右侧的cat命令,作为命令的参数执行。

使用-d参数指定制表符\t作为分隔符:

echo -e "a\tb\tc" | xargs -d "\t" echo
# a b c

使用-p参数打印要执行的命令,询问是否要执行:

find ./ | xargs -p rm -f
rm -f ./ ./test_ae ./test_ac ./test_am ?...

locate

搜索包含关键字的所有文件和目录。后接需要查找的文件名,也可以用正则表达式。

安装 locate

yum -y install mlocate	--> 安装包
updatedb	--> 更新数据库
locate file.txt
locate fil*.txt

[注意] locate 命令会去文件数据库中查找命令,而不是全磁盘查找,因此刚创建的文件并不会更新到数据库中,所以无法被查找到,可以执行 updatedb 命令去更新数据库。

which

which 查看可执行文件的位置。

find

用于查找文件,它会去遍历你的实际硬盘进行查找,而且它允许我们对每个找到的文件进行后续操作,功能非常强大。

find <路径> <选项> <操作>
  • 路径:指定在哪个目录查找,此目录的所有子目录也会被查找。
  • 选项:查找什么,可以根据文件的名字来查找,也可以根据其大小来查找,还可以根据其最近访问时间来查找。
  • 操作:找到文件后,可以进行后续处理,如果不指定这个参数, find 命令只会显示找到的文件。

参考文章:【链接】 《Linux 中使用 find 命令查找文件》

根据文件名查找

find -name "file.txt"	--> 当前目录以及子目录下通过名称查找文件
find . -name "syslog"	--> 当前目录以及子目录下通过名称查找文件
find . -iname "aa"      --> 当前目录以及子目录下通过名称查找文件(忽略文件名字大小写)
find / -name "syslog"	--> 整个硬盘下查找syslog
find /var/log -name "syslog"	--> 在指定的目录/var/log下查找syslog文件
find /var/log -name "syslog*"	--> 查找syslog1、syslog2 ... 等文件,通配符表示所有
find /var/log -name "*syslog*"	--> 查找包含syslog的文件 

根据文件大小查找

find /var -size +10M	--> /var 目录下查找文件大小超过 10M 的文件
find /var -size -50k	--> /var 目录下查找文件大小小于 50k 的文件
find /var -size +1G	--> /var 目录下查找文件大小查过 1G 的文件
find /var -size 1M	--> /var 目录下查找文件大小等于 1M 的文件

根据文件最近访问/修改时间查找

find -name "*.txt" -atime -7 	--> 近 7天内访问过的.txt结尾的文件
find /home/admin/datax3/log/ -mtime +n  --> n天外修改过的文件
find /home/admin/datax3/log/ -mtime -n  --> n天内修改过的文件

仅查找目录或文件

find . -name "file" -type f 	--> 只查找当前目录下的file文件
find . -name "file" -type d 	--> 只查找当前目录下的file目录

操作查找结果

find -name "*.txt" -printf "%p - %u\n"	--> 找出所有后缀为txt的文件,并按照 %p - %u\n 格式打印,其中%p=文件名,%u=文件所有者
find -name "*.jpg" -delete	--> 删除当前目录以及子目录下所有.jpg为后缀的文件,不会有删除提示,因此要慎用
find -name "*.c" -exec chmod 600 {} \;	--> 对每个.c结尾的文件,都进行 -exec 参数指定的操作,{} 会被查找到的文件替代,; 是必须的结尾
find -name "*.c" -ok chmod 600 {} \;	--> 和上面的功能一直,会多一个确认提示

grep

全局搜索一个正则表达式,并且打印到屏幕。简单来说就是,在文件中查找关键字,并显示关键字所在行。

基础语法

grep text file # text代表要搜索的文本,file代表供搜索的文件

# 实例
[root@lion ~]# grep path /etc/profile
pathmunge () {
    pathmunge /usr/sbin
    pathmunge /usr/local/sbin
    pathmunge /usr/local/sbin after
    pathmunge /usr/sbin after
unset -f pathmunge

常用参数

  • -i 忽略大小写, grep -i path /etc/profile 
  • -n 显示行号,grep -n path /etc/profile
  • -v 只显示搜索文本不在的那些行,grep -v path /etc/profile
  • -r 递归查找, grep -r hello /etc ,Linux 中还有一个 rgrep 命令,作用相当于 grep -r 
  • -F 不按照正则表达式匹配,按照字面意思匹配

高级用法

grep 可以配合正则表达式使用。

grep -E path /etc/profile --> 完全匹配path
grep -E ^path /etc/profile --> 匹配path开头的字符串
grep -E [Pp]ath /etc/profile --> 匹配path或Path

sed

stream Editor 的缩写,流编辑器,对标准输出或文件逐行进行处理。

语法格式

sed [option] "pattern/command" file

例如:
sed '/python/p' name.txt # 省略了option,/python/为pattern正则,p为command命令打印的意思
复制代码

[注意] 匹配模式中存在变量要使用双引号。

选项 option

-n 只打印模式匹配行
sed 'p' name.txt # 会对没一行字符串输出两遍,第一遍是原文本,第二遍是模式匹配到的文本
sed -n 'p' name.txt # 加了-n参数后就只打印模式匹配到的行
-e 默认选项

支持多个 pattern command 的形式

sed -e "pattern command" -e "pattern command" file
-f 指定动作文件
# 简单命令
sed -n '/python/p' name.txt # 但是一旦正则比较复杂,我们就可以把它保存在一个单独文件中,使用-f进行指定

# edit.sed 内容为 /python/p

sed -n -f edit.sed name.txt # '/python/p'这个命令保存在edit.sed文件中,使用-f指定
-E 扩展表达式
sed -n -E '/python|PYTHON/p' name.txt
-i 直接修改文件内容
sed -i 's/love/like/g' name.txt # -i修改原文件,全局love替换为like

模式匹配 pattern

pattern 用法表

匹配模式含义用法
10command 匹配到第10行sed -n "17p" name.txt  打印 name 文件的第17行
10,20command 匹配从第10行开始,到第20行结束sed -n "10,20p" name.txt 打印 name 文件的10到20行
10,+5command 匹配从第10行开始,到第15行结束sed -n "10,+5p" name.txt 
/pattern1/command 匹配到 pattern1 的行sed -n "/^root/p" name.txt 打印 root 开头的行
/pattern1/,/pattern2/command 匹配到 pattern1 的行开始,至匹配到 pattern2 的行结束sed -n "/^ftp/,/^mail/p" name.txt 
10,/pattern1/command 匹配从第10行开始,到匹配到 pattern1 的行结束sed -n "4,/^ok/p" name.txt 打印 name 文件从第4行开始匹配,直到以 ok 开头的行结束
/pattern1/,10command 匹配到 pattern1 的行开始,到第10行匹配结束sed -n "/root/,10p" name.txt 

命令 command

  • 查询

    • p -- 打印
  • 增加

    • a -- 行后追加
    • i -- 行前追加
    • r -- 外部文件读入,行后追加
    • w -- 匹配行写入外部文件
  • 删除

    • d -- 删除
  • 修改

    • s/old/new -- 将行内第一个 old 替换为 new
    • s/old/new/g -- 将行内全部的 old 替换为 new
    • s/old/new/2g --同一行,只替换从第二个开始到剩下所有的
    • s/old/new/ig -- 将行内 old 全部替换为 new ,忽略大小写

实例:

sed '/python/p' name.txt # 打印

sed '1d' name.txt # 删除第一行

sed -i '/frank/a hello' name.txt # 匹配到字符串frank就在这一行后面插入“hello”
sed -i '/frank/r list' name.txt # 把list文件内容追加到匹配frank字符串后面的行
sed -n '/frank/w tmp.txt' name.txt # 将匹配到frank的行全部写入tmp.txt文件中

sed -i 's/love/like/g' name.txt # 全局替换love为like,并修改源文件

反向应用

引用前面的匹配到的字符。

假设有一个文件 test.txt 内容为:

a heAAo vbv
c heBBo sdsad
k heCCo mnh

现在需要匹配到 heAAo heBBo heCCo 并在他们后面添加 s 。

使用反向引用可以这样做:

sed -i 's/he..o/&s/g' test.txt # 其中&就是引用前面匹配到的字符
sed -i 's/(he..o)/\1s/g' test.txt # 与上面的写法等价

# 输出结果
a heAAos vbv
c heBBos sdsad
k heCCos mnh

日志清理脚本

#!/bin/bash
echo "`date +"%Y-%m-%d %H:%M:%S"` start to clean log"
df -h | grep '/dev/vda1' | awk '{print $5}' | test $(sed 's/%//') -gt 80

if [ $? = 0 ]; then
 find /home/admin/logs/ -type f -mtime +3 -exec rm -rf {} \;
 find /home/admin/logs/ -type f -size +1G -exec rm -rf {} \;
fi
echo "`date +"%Y-%m-%d %H:%M:%S"` finish to clean log"
#!/bin/sh
df -h |grep '/dev/vdb' |awk '{print $5}'|test $((`sed 's/\%//'`)) -gt 60;
if [ $? = 0 ];then
  for i in `find /mnt/disk1/log -type f -mtime +3`;
    do echo '' > $i;
  done
  for i in `find /mnt/disk1/log -type f -type f -size +1G`;
    do echo '' > $i;
  done
fi

netstat练习1-查看各个状态的连接数

题目:链接

假设netstat命令运行的结果我们存储在nowcoder.txt里,格式如下:

Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:6160            0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 172.16.56.200:41856     172.16.34.144:3306      ESTABLISHED
tcp        0      0 172.16.56.200:49822     172.16.0.24:3306        ESTABLISHED
tcp        0      0 172.16.56.200:49674     172.16.0.24:3306        ESTABLISHED
tcp        0      0 172.16.56.200:42316     172.16.34.144:3306      ESTABLISHED
tcp        0      0 172.16.56.200:44076     172.16.240.74:6379      ESTABLISHED
tcp        0      0 172.16.56.200:49656     172.16.0.24:3306        ESTABLISHED
tcp        0      0 172.16.56.200:58248     100.100.142.4:80        TIME_WAIT
tcp        0      0 172.16.56.200:50108     172.16.0.24:3306        ESTABLISHED
tcp        0      0 172.16.56.200:41944     172.16.34.144:3306      ESTABLISHED
tcp        0      0 172.16.56.200:35548     100.100.32.118:80       TIME_WAIT
tcp        0      0 172.16.56.200:39024     100.100.45.106:443      TIME_WAIT
tcp        0      0 172.16.56.200:41788     172.16.34.144:3306      ESTABLISHED
tcp        0      0 172.16.56.200:58260     100.100.142.4:80        TIME_WAIT
tcp        0      0 172.16.56.200:41812     172.16.34.144:3306      ESTABLISHED
tcp        0      0 172.16.56.200:41854     172.16.34.144:3306      ESTABLISHED
tcp        0      0 172.16.56.200:58252     100.100.142.4:80        TIME_WAIT
tcp        0      0 172.16.56.200:49586     172.16.0.24:3306        ESTABLISHED
tcp        0      0 172.16.56.200:41754     172.16.34.144:3306      ESTABLISHED
tcp        0      0 172.16.56.200:50466     120.55.222.235:80       TIME_WAIT
tcp        0      0 172.16.56.200:38514     100.100.142.5:80        TIME_WAIT
tcp        0      0 172.16.56.200:49832     172.16.0.24:3306        ESTABLISHED
tcp        0      0 172.16.56.200:52162     100.100.30.25:80        ESTABLISHED
tcp        0      0 172.16.56.200:50372     172.16.0.24:3306        ESTABLISHED
tcp        0      0 172.16.56.200:50306     172.16.0.24:3306        ESTABLISHED
tcp        0      0 172.16.56.200:49600     172.16.0.24:3306        ESTABLISHED
tcp        0      0 172.16.56.200:41908     172.16.34.144:3306      ESTABLISHED
tcp        0      0 172.16.56.200:60292     100.100.142.1:80        TIME_WAIT
tcp        0      0 172.16.56.200:37650     100.100.54.133:80       TIME_WAIT
tcp        0      0 172.16.56.200:41938     172.16.34.144:3306      ESTABLISHED
tcp        0      0 172.16.56.200:49736     172.16.0.24:3306        ESTABLISHED
tcp        0      0 172.16.56.200:41890     172.16.34.144:3306      ESTABLISHED
udp        0      0 127.0.0.1:323           0.0.0.0:*
udp        0      0 0.0.0.0:45881           0.0.0.0:*
udp        0      0 127.0.0.53:53           0.0.0.0:*
udp        0      0 172.16.56.200:68        0.0.0.0:*
udp6       0      0 ::1:323                 :::*
raw6       0      0 :::58                   :::*                    7

现在需要你查看系统tcp连接中各个状态的连接数,并且按照连接数降序输出。你的脚本应该输出如下:

ESTABLISHED 22
TIME_WAIT 9
LISTEN 3

结果命令:

grep "tcp" nowcoder.txt | awk '{print $6}' | sort | uniq -c | awk '{print $2, $1}' | sort -nr -k 2

打印1-500内 7 的倍数

$cat nowcoder.sh
#!/bin/bash
for i in {1..500}
do
if [ $(($i % 7)) == 0 ]
then
echo $i
fi
done