Shell脚本实践总结
对比大小
符号用法:(必须使用双括号)
< 小于 (( "$a" < "$b" ))
<= 小于等于 (( "$a" <= "$b" ))
> 大于 (( "$a" > "$b" ))
>= 大于等于 (( "$a" >= "$b" ))
比大小命令用法:
-eq 等于 if [ "$a" -eq "$b" ]
-ne 不等于1 if [ "$a" -ne 1 ]
-gt 大于2 if [ "$a" -gt 2 ]
-ge 大于等于3 if [ "$a" -ge 3 ]
-lt 小于 if [ "$a" -lt "$b" ]
-le 小于等于 if [ "$a" -le "$b" ]
对比脚本:
#!/bin/sh
description=$(cat /tmp/abc.txt |grep 'SYSTEM-A:'|wc -l)
if [ ${description} -eq 0 ];then
cat << EOF >> /tmp/abc.txt
#####################################
# APPSYSTEM: 系统的名字是啥
# SYSTEM-A: 系统管理员A角
# SYSTEM-B: 系统管理员B角
#DESCRIPTION: 这台机器干啥的
#####################################
EOF
elif [ $description -eq 1 ];then
echo "文件中存在冲突配置,请手动检查,不可以自动修改"
else
echo "重复配置了${description}次"
fi
判断是否 为“空”还是 为“0”
if [ -z "$work" ] 和 if [ "$work" -eq 0 ]的区别
if [ -z "$work" ]
检查变量是否为空字符串。
if [ "$work" -eq 0 ]
检查变量是否等于数字 0。
if [ -z "$work" ] 和 if [ "$work" -eq 0 ] 是两种不同的条件判断语句,用于检查变量的值是否满足特定条件。
if [ -z "$work" ]:
这个条件判断语句用于检查变量 "$work" 是否为空。如果变量值为空字符串,也就是没有内容,那么条件成立,if 语句块内的代码将被执行。
if [ "$work" -eq 0 ]:
这个条件判断语句用于检查变量 "$work" 是否等于数字 0。如果变量值等于 0,那么条件成立,if 语句块内的代码将被执行。
这两种条件判断的区别在于对变量内容的检查方式不同,第一种检查空字符串,第二种检查数值。你应该根据你的具体需求选择适合的条件判断方式。
单引号、双引号、飘号的用法:为了防止空格、tab、等号等符号将字段隔开,我们将使用括号将他们视为一个整体
飘号 ` ` :执行内的命令
单引号 ' ' :单引号所括内容将被视为一字符串(请加深理解),像$等字符不会被执行。
双引号 " " :双引号所括内容将被视为一字符串(请加深理解),它防止通配符扩展,但允许变量扩展,即像$符这种指令是会执行的。
如果不想执行可在$前加上转义字符 \,或改为单引号。 (就像sqoop指令中SQL语句后的$conditions 前就必须加转义字符,否则会在双引号内被提前解析)
举例脚本
#!/bin/bash
do_date=$1
echo '$do_date' #单引号--所见即所得
echo "$do_date" #双引号--翻译内部
echo "'$do_date'" #双引号套用单引号
echo '"$do_date"' #单引号套用双引号
echo `date` #飘号--执行飘号内的命令
运行结果为
root@zys-t02:/root# bash test.sh 2020-06-14
$do_date #单引号--所见即所得
2020-06-14 #双引号--翻译内部
'2020-06-14' #双引号套用单引号
"$do_date" #单引号套用双引号
2023年 01月 10日 星期四 16:02:08 CST #飘号--执行飘号内的命令
总结单双和反引号用法:
(1)单'引号'不取变量值,直接输出
sed -i ${Num_TMOUT}'c #export TMOUT参数已注释' /etc/profile
(2)双"引号"取变量值后输出
sed -i ${Num_TMOUT}"c \#export TMOUT参数已注释" /etc/profile
(3)`飘号`执行飘号中命令
(4)外双引号+内单引号,取出变量值
特殊情况:使用额外的单引号对冲来解决
取行号脚本
#!/bin/bash
Repair_TMOUT=`cat /etc/profile | grep "^export TMOUT" | head -n1`
#head -n1前1行,tail -n2后2行
if [ "$Repair_TMOUT" ];then
#标准用法是
LIN_NUM=$(sed -n '/匹配内容/=' /etc/profile)
方法一#使用变量时用外单引号+内双引号解决
LIN_NUM=$(sed -n '/'"$Repair_TMOUT"'/=' /etc/profile)
方法二#还是用双引号简单
LIN_NUM=$(sed -n "/${Repair_TMOUT}/=" /etc/profile)
方法三#一条命令
sed -n "/^export TMOUT/=" /etc/profile
方法四#一条命令
cat /etc/profile |grep -n ^"export TMOUT"|awk -F[:] '{print $1}'
(5)外单引号+内双引号,不取出变量值永远直接输出
举例:
echo $(date) #执行date命令--取值--输出
echo `date` #飘号是执行内容,类似于上面的$(XXX)。这里`data`==$(date)
这两条的运行结果都是:
2020年 06月 18日 星期四 21:02:08 CST
运行
echo date
结果为:
特殊符号意义
head -n1
tail -n1
awk 'NR==3 {print}' file.txt
#查询最后一行
awk 'END {print}' file.txt
sed -n '$p' file.txt
tail -n 1 file.txt
#查询第一行
awk 'NR==1 {print}' file.txt
sed -n '1p' file.txt
head -n 1 file.txt
sed -i 插入|替换|删除
插入
标准格式:2种写法结果都一样,但推荐将引号放在行号后面,因为出现变量时好处理
sed -i 1'i abc 123 xyz' /tmp/test.txt #在第1行之前插入abc 123 xyz
sed -i '1i abc 123 xyz' /tmp/test.txt #在第1行之前插入abc 123 xyz
演变格式1: i前、a后、c替换
sed -i 1'i abc 123 xyz' /tmp/test.txt #在第1行之前插入abc 123 xyz
sed -i 2'a efg' /tmp/test.txt #在第2行之后插入efg
sed -i 3'c xyz wd 555' /tmp/test.txt #把第3行数据替换成xyz wd 555
演变格式2:使用函数,注意双引号" "和单引号' '的区别
INT=66
sed -i 3'c $INT 123 xyz' /tmp/test.txt #把第3行数据替换成$char 123 xyz
sed -i 3"c $INT 123 xyz" /tmp/test.txt #把第3行数据替换成666 123 xyz
sed -i $INT"c $INT 123 xyz" /tmp/test.txt #把第66行数据替换成66 123 xyz
sed -i $INT'c $INT 123 xyz' /tmp/test.txt #把第66行数据替换成$INT 123 xyz
此时如果把单引号或者双引号放在外面就比较麻烦
双引号这种格式想解决就要严格要求里面的各种格式
甚至需要用外单引号对冲来解决问题,非常不建议使用
替换
几种写法:#把第1行数据替换成abc 123 haha 推荐使用双引号格式,参考双引号和单引号的区别
sed -i 1"c abc 123 haha" /tmp/abc.txt#最推荐格式
sed -i 1'c abc 123 haha' /tmp/abc.txt
sed -i "1c abc 123 haha" /tmp/abc.txt
sed -i '1c abc 123 haha' /tmp/abc.txt
变种举例:
Num=6
sed -i 1'c abc 123 haha' /tmp/abc.txt 把第1行数据替换成abc 123 haha
sed -i 2'c ${Num} 123 haha' /tmp/abc.txt 把第2行数据替换成${Num} wd 555 不转译
sed -i 3"c ${Num} 123 haha" /tmp/abc.txt 把第3行数据替换成(Num变量的值)6 123 haha 转译
sed -i ${Num}"c abc ${Num} haha" /tmp/abc.txt 把第(Num变量值)的行数,据替换成 abc 6 haha#最推荐格式
sed -i 's 新字符串 替换 原字符串
双引号和单引号均可以,参考双引号和单引号的区别
sed -i "s/原字符串/新字符串/" /home/1.txt #每行只执行一次
sed -i "s/原字符串/新字符串/g" /home/1.txt #每行执行多次
举例:
#cat 1.txt的内容如下
d
ddd
#ff
sed -i "s/d/7523/" /home/1.txt
执行结果
7523
7523dd
#ff
sed -i "s/d/7523/g" /home/1.txt
执行结果
7523
752375237523
#ff
替换第几行文字 "c
sed -i 1"c xyz wd 555" /tmp/abc.txt
sed -i ${line_num}"c MaxAuthTries 5" /etc/ssh/sshd_config
line_num=$(sed -n "/^MaxAuthTries/=" /etc/ssh/sshd_config)
#找出/etc/ssh/sshd_config路径下的【^MaxAuthTries】字段的行数,赋值给line_num
sed -i ${line_num}"c MaxAuthTries 5" /etc/ssh/sshd_config
#用这个line_num行数取值,替换掉这一行为【MaxAuthTries 5】
删除变量表示的行号 (可配合for等语句使用)
双引号和单引号均可以,参考双引号和单引号的区别
sed -i "${var1}d" /etc/abc.txt
#这里引号必须为双引号
删除第N~M行
sed -i 'N,Md' filename #file的[N,M]行都被删除
sed -i "${var1},${var2}d" /etc/abc.txt
#这里引号必须为双引号
删除包含指定字符串的整行sed -i ——/d(删除)
sed -i '/字符串/d' /etc/hosts
双引号和单引号均可以,参考双引号和单引号的区别
sed -i '/ntpserver/d' /etc/hosts
#删除/etc/hosts 里包含ntpserver的行
多层查询(以下两种方法结果相同)grep -v (非)
#查询/tmp/abc.txt文件 | 有【host name】| 不是以#开头的 | 计数
cat /tmp/abc.txt | grep 'host name'| grep -v ^#| wc -l
#查询/tmp/abc.txt文件 | 以【host name】开头的 | 计数
cat /tmp/abc.txt | grep ^'host name'| wc -l
for循环控制语句的3种用法
declare是bash的一个内建命令,可以用来声明shell变量、设置变量的属性。
declare也可以写作typeset。declare -i sum 代表强制把sum变量当做int型参数运算。
用法1:
for ((初始值;限制值;执行步阶))
do
程序段
done
初始值:变量在循环中的起始值
限制值:当变量值在这个限制范围内时,就继续进行循环
执行步阶:每作一次循环时,变量的变化量
#!/bin/bash
declare -i sum
sum=0
for ((i=0;$i<=10;i=$i+1))
do
sum=$sum+$i
done
echo "sum=$sum"
用法2:for in + 固定范围内
for num in 1 2 3 4 5
do
echo "$num"
done
用法3:for in + 执行语句
#!/bin/bash
declare -i num LIN_NUM
timeout=$(cat ccc |grep "^TMOUT" |head -n1)
num=1
if [ "$timeout" ];then
for q in `cat ccc |grep -n "^TMOUT="`
do
LIN_NUM=$(echo $q |awk -F':' '{print $1}')
if [ $num == 1 ];then
sed -i $LIN_NUM'c TMOUT=600' ccc
num=$num+1
echo $LIN_NUM
else
sed -i "${LIN_NUM}c \#TMOUT参数已替换" ccc
num=$num+1
echo $LIN_NUM
fi
done
fi
#仅修改第一个匹配到的目标,其余的目标替换为“#TMOUT参数已替换”
函数赋值:执行命令后赋值,需要使用$( )或者` `
Num=$(cat /etc/ssh/sshd_config | grep ^PasswordAuthentication |wc -l)
或者
Num=`cat /etc/ssh/sshd_config | grep ^PasswordAuthentication |wc -l`