前言
好多shell脚本,写过就扔了,感觉很可惜。本文会不断更新,用于记录自我感觉良好的脚本。以后再遇到相似的需求,方便进行参考查找。
如果想要系统学习Bash,推荐学习阮一峰前辈的《Bash 脚本教程》。
短脚本
查看系统版本
1 | lsb_release -a |
查看命令属于哪个包
1、centos
1 | yum makecache fast |
2、ubuntu
1 | apt-get install -y apt-file |
创建用户
创建voidking用户,并添加sudo权限:
1 | useradd -m voidking -s /bin/bash |
过滤空行
过滤hostlist.txt中的空行(linux和windows空行都进行过滤):
1 | grep -v -e '^[[:space:]]*$' ng.txt |
过滤windows换行符
在windows里编辑好的文件,上传到linux后发现多了^M。以过滤hostlist.txt中的^M为例:
1 | sed -i 's/^M//g' hostlist.txt |
注意,直接复制粘贴上面的命令是无效的。^M的输入方式是 Ctrl + V ,然后 Ctrl + M 。
去除空格
去除test.txt文本中的空格:
1 | cat test.txt | tr -d ' ' |
空格转换行
把test.txt文本中的空格变成换行符。
1 | cat test.txt | tr ' ' '\n' |
utf8 bom 转 utf8
使用macos中编译运行windows下创建的java项目,报错 Error:(1, 1) java: 非法字符: ‘\ufeff’。
BOM(byte order mark)是为 UTF-16 和 UTF-32 准备的,用于标记字节序(byte order)。
微软在 UTF-8 中使用 BOM 是因为这样可以把 UTF-8 和 ASCII 等编码明确区分开,但这样的文件在 Windows 之外的操作系统里会带来问题。
那么,怎么把utf8 bom编码文件批量转换为utf8编码文件呢?使用下面的脚本。
1 | 当前目录下递归所有文件 |
循环读取单列文本
已知hostlist.txt为:
1 | www.baidu.com |
需求:批量查询主机名或者主机IP
脚本:
1 | for i in `cat hostlist.txt`;do host $i;done |
文本比较
需求:两个姓名列表,需要对比出两个文件中相同的姓名和不同的姓名。
脚本:
1 | cat file1 > file.txt |
批量添加开机启动命令
已知主机列表hosts.txt内容为:
1 | 192.168.56.101 |
需求:给主机列表中的机器添加开机启动命令
脚本:
1 | for i in `cat hosts.txt`; do ssh $i "echo '/home/voidking/start.sh' | sudo tee -a /etc/rc.local";done |
curl post请求带参数
1、application/x-www-form-urlencoded
请求:
1 | id=1 |
2、application/json
请求:
1 | curl -H "Content-type: application/json" -X POST -d '{"id":"'${id}'","ip":"'${ip}'"}' http://rap2api.taobao.org/app/mock/241888/updateip |
3、multipart/form-data
请求:
1 | curl -F "id=${id}" -F "filename=@file.tar.gz" http://rap2api.taobao.org/app/mock/241888/updateip |
EPEL源
EPEL(ExtraPackagesforEnterpriseLinux)是基于Fedora的一个项目,为RedHat系的操作系统提供额外的高质量软件包。yum install epel-release
安装epel源之后,可以安装很多原本 No package xxx available 的软件,比如jq:yum install jq
联合查询
使用shell,能否实现类似于SQL的联合查询?必须可以。
已知file1的内容为:
1 | 1 realname |
file2的内容为:
1 | voidking nickname |
需求:根据file1和file2的第二列,把file1和file2合并成一个文件。
1 | 2 voidking nickname |
这个需求使用awk命令来实现。
NR,表示awk开始执行程序后所读取的数据行数。
FNR,与NR功用类似,不同的是awk每打开一个新文件,FNR便从0重新累计。
NR==FNR:用于在读取两个或两个以上的文件时,判断是不是在读取第一个文件。
awk处理多个文件的语法:
1 | awk -F 分隔符 'BEGIN { 初始化 } { 循环执行部分 } END { 结束处理 }' file_list1 file_list2 |
其中BEGIN和END可以省略,-F也可以使用默认,循环执行部分,是按行对文件进行处理的。
脚本:
1 | awk -F " " 'NR==FNR{a[$2]=$0;next}{print a[$2]" "$1}' file1 file2 \ |
由NR=FNR为真时,判断当前读入的是第一个文件file1,执行第一个花括号内的内容。
把file1中每行记录都存入数组a,并使用file1的第2个字段作为下标。
由NR=FNR为假时,判断当前读入了第二个文件file2,执行第二个花括号内的内容。
file2中的每行,根据file2的第2个字段打印数组a中的内容,同时打印file2中的第一列。
每两行合成一行
已知ip-port.txt内容为:
1 | 127.0.0.1 |
需求:把ip和对应端口放在同一行。
1 | 127.0.0.1 80 |
脚本:
1 | awk 'NR%2{printf "%s ",$0;next;}1' ip-port.txt |
删除10天前的日志
需求:找出10天前的日志并删除。
脚本:
1 | find /usr/local/tomcat/logs/ -type f -mtime +10 -exec rm -rfv {} \; |
计算一列的和
已知fruit.txt内容为:
1 | apple 10 |
第一列是水果名称,第二列是水果数量。
需求1:计算水果的总数。
1 | awk '{sum += $2};END {print sum}' fruit.txt |
需求2:计算存在多少种水果。
1 | cat fruit.txt | awk '{if ($2>0) (sum += 1); else (sum += 0)};END{print sum}' |
重定向
0 标准输入
1 标准输出,默认指向屏幕
2 错误输出,默认指向屏幕
/dev/null 黑洞
1 | # 标准输出重定向到文件 |
清空文件内容
需求:清空text.txt文件中的内容
脚本:
1 | echo "" > test.txt |
测试mtu值
MTU是Maximum Transmission Unit的缩写,表示最大传输单元,MTU的单位是字节。大部分网络设备的MTU都是1500。
把本机的MTU设成比网关的MTU小或相同,就可以减少丢包。如果本机的MTU比网关的MTU大,大的数据包就会被拆开来传送,这样会产生很多数据包碎片,增加丢包率。
把数据包长度加上数据包头28字节,就得到MTU的值。
1 | ping -c 3 -s 1472 -M do www.baidu.com |
获取脚本绝对路径
1 | scriptpath=$(cd "$(dirname "$0")"; pwd) |
长脚本
循环读取多列文本1.0
已知mobile.txt为:
1 | haojin 17625160000 |
需求:拼接成SQL,实现根据name修改mobile。
脚本:
1 |
|
PS:不能使用for line in cat 'mobile.txt'
,因为这种方法会按照空格或换行切分文本。
循环读取多列文本2.0
以上循环读取的方法是存在一些问题的,我们再来看另外一个需求。
已知service.txt内容为:
1 | 127.0.0.1 80 |
需求:探测service.txt中每个服务的连通性,并记录结果。
脚本:
1 |
|
执行脚本后,我们发现结果文件中只有一条结果!这就不符合预期了。
这是因为while使用重定向机制,while read line
一次性将文件信息读入输入缓存,并按行赋值给变量line,直到输入缓存数据为空。而刚好nc、telnet、ssh等命令,会读取输入缓存中的所有数据,这就导致输入缓存被清空了,while循环结束。
解决办法:
1 | res=$(nc -w 2 -v $ip $port < /dev/null) |
除此之外,1.0版本管道符后的while实际上是在子shell中执行,变量赋值等不会在父shell中生效,容易引发其他问题。因此,最终的脚本应该改成:
1 |
|
参数提示和校验
需求:有一个脚本,需要appname、ip、hostname、domain四个参数,并且都不能为空。
脚本:
1 |
|
执行SQL语句
需求:mysql数据库,获取数据库vk中的app表中所有记录的name,写入到 name.txt 文件。
脚本:
1 |
|
模拟面试
已知 quiz.txt 内容为:
1 | 介绍 Java 垃圾回收器的基本原理。 |
需求:从 quiz.txt 文本中,随机选出5道题(不能重复),作为面试题目。面试结束后,发送面试题目到指定邮箱,方便回顾思考。
脚本:
1 |
|