Shell脚本字符串匹配及日常命令工具 - 用法总结(技巧指南)
Shell提供了很多字符串和文件处理的命令,如awk、expr、grep、sed等命令,还有文件的排序、合并和分割等一系列的操作命令。下面重点总结下Shell字符串处理、文本处理以及各类命令及函数用法。
先从expr命令开始梳理,expr 引出通用求值表达式,可以实现算术操作、比较操作、字符串操作和逻辑操作等功能。
1) 计算字符串长度
字符串名为string,可以使用命令 ${#string} 或 expr length ${string} 两种方法来计算字符串的长度。
若string中包括空格,则expr计算命令中需用双引号引起来,即expr length "${string}"。(${#string}方法对于有无空格的字符串均可使用)
需要注意:expr length后面只能跟一个参数,string有空格会当作多个参数处理。
[root@kevin ~]# string="kevinisgood"
[root@kevin ~]# expr length ${string}
11
[root@kevin ~]# expr length "${string}"
11
[root@kevin ~]# echo ${#string} # 使用自带shell函数读取字符串长度
11 如果string字符串中有空格
[root@kevin ~]# string="kevin is good"
[root@kevin ~]# expr length ${string}
expr: syntax error
[root@kevin ~]# expr length "${string}"
13
[root@kevin ~]# echo ${#string}
13 注意:这里说到如果string字符串中有空格,则需要双引号引起来。但如果是单引号引起来呢?
如果string字符串用单引号引起来,则统计出来的是"字符串去重和去掉空格"后的长度 [root@kevin ~]# echo ${string}
kevin is good
[root@kevin ~]# expr length '${string}' #使用单引号的话,统计的是"字符去重以及去掉空格"之后的长度
9 [root@kevin ~]# string="kevinisgood"
[root@kevin ~]# echo ${string}
kevinisgood
[root@kevin ~]# expr length '${string}'
9
2)匹配字符串长度
即匹配字符串开头子串的长度!!使用命令 expr match ${string} $substring,表示在string字符串的开头匹配substring字符串,返回匹配到的substring字符串的长度。若string开头匹配不到则返回0,其中substring可以是字符串也可以是正则表达式。
expr匹配字符串长度的两种格式:
# expr match "$string" '$substring'
# expr "$string" : '$substring' [root@kevin ~]# string="zhongguo hao"
[root@kevin ~]# expr length "${string}"
12
[root@kevin ~]# expr match "${string}" "z.*"
12
[root@kevin ~]# expr match "${string}" "zho"
3
[root@kevin ~]# expr match "${string}" "hao"
0 注意:
"hao"尽管在string字符串中出现,但是未出现在string的开头处,因此返回0!
所以说,expr match匹配的一定是字符串开头子串的长度!! 后面的$substring可以是正则, $substring两边是单引号或双引号无所谓。
[root@kevin ~]# string="KEvin IS good"
[root@kevin ~]# expr match "${string}" "[A-Z]*"
2
[root@kevin ~]# expr match "${string}" '[A-Z]*'
2 [root@kevin ~]# expr "${string}" : "[A-Z]*" #注意这种方法中就没有了"match"参数
2
[root@kevin ~]# expr "${string}" : '[A-Z]*[a-z]*'
5
3)匹配字符串索引
expr的索引命令格式为:expr index ${string} $substring。
在字符串$string上匹配$substring中字符最早第一次出现的位置(从左到右,从1开始),匹配不到,expr index返回0。
简单来说,就是找出子串在字符串中最早第一次出现的单个字符的位置!!
[root@kevin ~]# string="love beijing"
[root@kevin ~]# echo ${string}
love beijing
[root@kevin ~]# expr index ${string} "bei"
expr: syntax error
[root@kevin ~]# expr index "${string}" "bei" #注意string字符串中有空格,需要加双引号
4
[root@kevin ~]# expr index "${string}" "jing"
8
[root@kevin ~]# expr index "${string}" "haa"
0 注意:
expr index命令中返回的是后面$substring中"子串字符中"最早第一次出现的位置。
"bei"子串中在${string}字符串中最早第一次出现的是"e",第4位置
"jing"子串中在${string}字符串中最早第一次出现的是"i",第4位置
"haa"匹配不到,所以返回0!
=== Bash Shell命令 ===
4)抽取字符串的子串
Shell提供两种命令和expr实现抽取子串功能。
正着抽取(即从左到右)有两种格式。(左边默认从0开始标号)
格式一:{string:position} 从名称为${string}的字符串的第$position个位置开始抽取子串,从0开始标号。
格式二:{string:position:length} 增加$length变量,表示从${string}字符串的第$position个位置开始抽取长度为$length的子串。 需要注意:都是从string的左边开始计数抽取子串。 示例:
[root@kevin ~]# string="hello world wang"
[root@kevin ~]# echo ${string}
hello world wang
[root@kevin ~]# echo ${string:0} #从标号为0(即从第一个字母)开始截取,截取到结尾。
hello world wang
[root@kevin ~]# echo ${string:6} #从标号为6的字符开始截取,截取到结尾。
world wang
[root@kevin ~]# echo ${string:6:4} #从标号为6的字符开始截取,截取长度为4。
worl
[root@kevin ~]# echo ${string:6:0} #从标号为6的字符开始截取,截取长度为0。 [root@kevin ~]# 反着抽取(即从右到左)有两种格式。(右边默认从-1开始标号)
格式一:{string: -position}。需要谨记:冒号与横杠间有一个空格!!!!
格式二:{string:(position)}。如果加了括号,则冒号后面加不加空格是一样的效果!!! [root@kevin ~]# echo ${string:-2} #冒号与"-"之间必要要有空格,否则截取无效!
hello world wang
[root@kevin ~]# echo ${string: -2}
ng [root@kevin ~]# echo ${string:(-2)}
ng
[root@kevin ~]# echo ${string: (-2)}
ng 如果要想实现从右边第几个字符开始截取,截取长度为多少,则方法为:
{string:m-n:x} 表示从右边第"m-n"个字符开始截取,截取长度为x
[root@kevin ~]# echo ${string:1-7:3}
d w
[root@kevin ~]# echo ${string:3-9:3}
d w expr substr也能够实现抽取子串功能,命令格式:expr substr ${string} $position $length,
这个与上面最大不同是expr substr命令从1开始进行标号!!!!
[root@kevin ~]# echo ${string}
hello world wang
[root@kevin ~]# echo ${string:3:5} #从0开始进行标号
lo wo
[root@kevin ~]# expr substr "${string}" 3 5 #从1开始标号
llo w 还可以使用正则表达式抽取子串的命令,但只能抽取string开头处或结尾处的子串。 抽取字符串开头处的子串:
格式一:expr match $string ''
格式二:expr $string : ''。 注意:其中冒号前后都有一个空格。 抽取字符串结尾处的子串:
格式一:expr match $string '.*'
格式二:expr $string : '.*'。 注意:.*表示任意字符的任意重复。一个.表示一个字符。 [root@kevin ~]# string="20181112hello WORld Good"
[root@kevin ~]# echo ${string}
20181112hello WORld Good
[root@kevin ~]# expr match "$string" '\([0-9]*\)' #这里的${string}最好使用双引号引起来,因为字符串可能中有空格!如果没有空格,就可以不用使用双引号。
20181112
[root@kevin ~]# expr match "$string" "\([0-9]*\)"
20181112
[root@kevin ~]# expr "$string" : '\([0-9]*\)'
20181112 [root@kevin ~]# expr match "$string" '.*\(.\)'
d
[root@kevin ~]# expr match "$string" '.*\(..\)'
od
[root@kevin ~]# expr match "$string" '.*\(...\)'
ood
[root@kevin ~]# expr match "$string" '.*\(.....\)'
Good
[root@kevin ~]# expr "$string" : '.*\(.....\)'
Good
[root@kevin ~]# expr "$string" : '.*\(.........\)'
ORld Good [root@kevin ~]# string="heLLO2018 world"
[root@kevin ~]# expr match "$string" '\([a-z]*\)'
he
[root@kevin ~]# expr match "$string" '\([a-Z]*\)'
heLLO
[root@kevin ~]# expr match "$string" '\([a-Z]*[0-9]*\)'
heLLO2018
[root@kevin ~]# expr match "$string" '\(.[a-Z]*[0-9]*\)'
heLLO2018 [root@kevin ~]# expr "$string" : '.*\(.........\)'
018 world
5)删除字符串的子串
删除字串是指将原字符串中符合条件的子串删除。
从string开头处删除子串:
格式一:${string#substring} 删除开头处与substring匹配的最短子串。
格式二:${string##substring} 删除开头处与substring匹配的最长子串。其中substring并非是正则表达式而是通配符。
[root@kevin ~]# string="china IS niuBIlity2018"
[root@kevin ~]# echo ${string#c*i} #删除c开头到a的最短子串
na IS niuBIlity2018
[root@kevin ~]# echo ${string##c*i} #删除c开头到a的最长子串
ty2018
[root@kevin ~]# echo ${string#c*n}
a IS niuBIlity2018
[root@kevin ~]# echo ${string##c*n}
iuBIlity2018
[root@kevin ~]# echo ${string#ch*n} #删除ch开头到a的最短子串
a IS niuBIlity2018
[root@kevin ~]# echo ${string##ch*n} #删除ch开头到a的最长子串
iuBIlity2018 上面#或##后面的字符必须是${string}字符串的开头子串!否则删除子串就无效了!
[root@kevin ~]# echo ${string#i*n} #i不是开头字符,所以删除无效
china IS niuBIlity2018
[root@kevin ~]# echo ${string##i*n} #i不是开头字符,所以删除无效
china IS niuBIlity2018 另外:可以使用下面方式进行删除:
${string#*substring} 删除${string}字符串中第一个$substring及其之前的字符
${string##*substring} 删除${string}字符串中最后一个$substring及其之前的字符
[root@kevin ~]# string="china IS niuBIlity2018"
[root@kevin ~]# echo ${string#*i} #删除第一个i及其之前的字符
na IS niuBIlity2018
[root@kevin ~]# echo ${string##*i} #删除最后一个i及其之前的字符
ty2018 也可以使用下面方法进行删除
格式一:${string%substring*} 删除${string}字符串中最后一个$substring及其之后的字符
格式二:${string%%substring*} 删除${string}字符串中第一个$substring及其之后的字符
[root@kevin ~]# echo ${string}
china IS niuBIlity2018
[root@kevin ~]# echo ${string%i*}
china IS niuBIl
[root@kevin ~]# echo ${string%%i*}
ch
[root@kevin ~]# echo ${string%c*} [root@kevin ~]# echo ${string%%c*} [root@kevin ~]#
6)字符串替换
替换子串命令可以在任意处、开头处、结尾处替换满足条件的子串,其中的substring都不是正则表达式而是通配符。
在任意处替换子串命令:
格式一:${string/substring/replacement},仅替换第一次与substring相匹配的子串。
格式二:${string//substring/replacement},替换所有与substring相匹配的子串。 [root@kevin ~]# string="china IS niuBIlity2018"
[root@kevin ~]# echo ${string/i/#}
ch#na IS niuBIlity2018
[root@kevin ~]# echo ${string//i/#}
ch#na IS n#uBIl#ty2018 [root@kevin ~]# echo ${string}
china IS niuBIlity2018
[root@kevin ~]# echo ${string/ /--} #替换空格
china--IS niuBIlity2018
[root@kevin ~]# echo ${string// /--}
china--IS--niuBIlity2018 在开头处替换与substring相匹配的子串,格式为:${string/#substring/replacement}。
在结尾除替换与substring相匹配的子串,格式为:${string/%substring/replacement}。
[root@kevin ~]# echo ${string}
china IS niuBIlity2018
[root@kevin ~]# echo ${string/#ch/he}
heina IS niuBIlity2018
[root@kevin ~]# echo ${string/#china/anhui}
anhui IS niuBIlity2018
[root@kevin ~]# echo ${string/#niu/he} #注意这里#后面的字符必须是${string}字符串中开头的字符
china IS niuBIlity2018 [root@kevin ~]# echo ${string/%2018/2020}
china IS niuBIlity2020
[root@kevin ~]# echo ${string/%lity2018/hehehe}
china IS niuBIhehehe
7)${!varprefix*} 和 ${!varprefix@}
[root@kevin ~]# test="bobo"
[root@kevin ~]# test1="bobo1"
[root@kevin ~]# test2="bobo2"
[root@kevin ~]# test4="bobo4"
[root@kevin ~]# echo ${!test*}
test test1 test2 test4
[root@kevin ~]# echo ${!test@}
test test1 test2 test4
8)参数替换
从string开头处删除子串:
格式一:${string#substring} 删除开头处与substring匹配的最短子串。
格式二:${string##substring} 删除开头处与substring匹配的最长子串。其中substring并非是正则表达式而是通配符。
[root@kevin ~]# string="china IS niuBIlity2018"
[root@kevin ~]# echo ${string#c*i} #删除c开头到a的最短子串
na IS niuBIlity2018
[root@kevin ~]# echo ${string##c*i} #删除c开头到a的最长子串
ty2018
[root@kevin ~]# echo ${string#c*n}
a IS niuBIlity2018
[root@kevin ~]# echo ${string##c*n}
iuBIlity2018
[root@kevin ~]# echo ${string#ch*n} #删除ch开头到a的最短子串
a IS niuBIlity2018
[root@kevin ~]# echo ${string##ch*n} #删除ch开头到a的最长子串
iuBIlity2018 上面#或##后面的字符必须是${string}字符串的开头子串!否则删除子串就无效了!
[root@kevin ~]# echo ${string#i*n} #i不是开头字符,所以删除无效
china IS niuBIlity2018
[root@kevin ~]# echo ${string##i*n} #i不是开头字符,所以删除无效
china IS niuBIlity2018 另外:可以使用下面方式进行删除:
${string#*substring} 删除${string}字符串中第一个$substring及其之前的字符
${string##*substring} 删除${string}字符串中最后一个$substring及其之前的字符
[root@kevin ~]# string="china IS niuBIlity2018"
[root@kevin ~]# echo ${string#*i} #删除第一个i及其之前的字符
na IS niuBIlity2018
[root@kevin ~]# echo ${string##*i} #删除最后一个i及其之前的字符
ty2018 也可以使用下面方法进行删除
格式一:${string%substring*} 删除${string}字符串中最后一个$substring及其之后的字符
格式二:${string%%substring*} 删除${string}字符串中第一个$substring及其之后的字符
[root@kevin ~]# echo ${string}
china IS niuBIlity2018
[root@kevin ~]# echo ${string%i*}
china IS niuBIl
[root@kevin ~]# echo ${string%%i*}
ch
[root@kevin ~]# echo ${string%c*} [root@kevin ~]# echo ${string%%c*} [root@kevin ~]# -------------------------------------------------------------------
再看下面一例:
[root@kevin ~]# str=bo/www/kevin/data/test/ccd.log
[root@kevin ~]# echo ${str#*/*/}
kevin/data/test/ccd.log
[root@kevin ~]# echo ${str##*/*/}
ccd.log [root@kevin ~]# echo ${str%/*/*}
bo/www/kevin/data
[root@kevin ~]# echo ${str%%/*/*}
bo 以上是以/*/作为匹配的字符串,即正则匹配的字符串。
9)如何判断一个字符串是否由字母数字开头 (grep)
1)判断一个字符串是否由大小写字母或数字开头(或结尾)
[root@kevin ~]# cat test.sh
#!/bin/bash
#str="This IS a root USER, 20171aaabb" read -p "请输入内容:" str if echo "${str}" | grep -q '^[A-Za-z0-9].*\+$'; then
echo -e "${str}\nok"
else
echo "invaliad"
fi 需要注意:
脚本中的echo后面只需要添加-e参数,是为了让打印中的\n换行符生效!如果不加-e参数,则\n就被做当普通字符打印出来了!
read -p 表示"指定要显示的提示"。如果添加-s参数,即"read -sp",则表示"静默输入,即隐藏输入的数据,一般用于密码输入" 执行脚本:
[root@kevin ~]# sh test.sh
请输入内容:TOOk213gg
TOOk213gg
ok [root@kevin ~]# sh test.sh
请输入内容:@#sadf123
invaliad [root@VM_16_9_centos ~]# sh test.sh
请输入内容:arTR213#$1
arTR213#$1
ok ==============================================================
[root@kevin ~]# read -p "输入你想要输入的内容:"
输入你想要输入的内容:asdfsafsaf [root@kevin ~]# read -sp "输入你想要输入的内容:" #加了-s参数后,即为静默输入,隐藏输入的内容
输入你想要输入的内容:
[root@kevin ~]#
============================================================== 为了简化,还可以将上面脚本中的:
grep -q '^[A-Za-z0-9].*\+$'
改为
grep -q '^[A-Za-z0-9].*' --------------------------------------
如果判断一个字符串是否由大小写字母或数字结尾!!!!! 则只需要将上面脚本中的:
grep -q '^[A-Za-z0-9].*\+$'
改为
grep -q '.*[A-Za-z0-9]$' ==============================================================
还要注意:
'^[A-Za-z0-9].*\+$' 表示以大写字母或小写字母或数字为开头。没有顺序要求!!
'^[A-Za-z0-9].*' 可以直接去掉后面的"\+$"部分
'^[A-Z].*' 表示以大写字母开头
'^[a-z].*' 表示以小写字母开头
'^[0-9].*' 表示以数字字母开头 下面都是最常用的
grep ^[0-9]
grep "^[0-9]"
grep ^[a-z]
grep "^[a-z]"
grep ^[A-Z]
grep "^[A-Z]" grep ^[a-Z]
grep "^[a-Z]" grep .*[0-9]$
grep ".*[0-9]$"
grep ".*[a-z]$"
grep ".*[a-z]$"
grep ".*[A-Z]$"
grep ".*[A-Z]$" grep .*[a-Z]$
grep ".*[a-Z]$" grep [0-9]G
grep [a-z]2018_data [root@kevin ~]# cat a.txt
Good study 2018! hahahah~
good Study 2018hehehehe
2018 Good study 1wqe
2018stuDY is heht6ttt
!@#asdf
TOOk213gg asdfasdf
anhui 2018asdfjlsadfdsaff
#$$$$$ [root@kevin ~]# cat a.txt|grep '^[A-Z].*\+$'
Good study 2018! hahahah~
TOOk213gg asdfasdf [root@kevin ~]# cat a.txt|grep '^[a-z].*\+$'
good Study 2018hehehehe
anhui 2018asdfjlsadfdsaff [root@kevin ~]# cat a.txt|grep '^[0-9].*\+$'
2018 Good study 1wqe
2018stuDY is heht6ttt [root@kevin ~]# cat a.txt|grep '^[A-Za-z0-9].*\+$'
Good study 2018! hahahah~
good Study 2018hehehehe
2018 Good study 1wqe
2018stuDY is heht6ttt
TOOk213gg asdfasdf
anhui 2018asdfjlsadfdsaff [root@kevin ~]# cat a.txt|grep -v '^[A-Za-z0-9].*\+$'
!@#asdf
#$$$$$ [root@kevin ~]# cat a.txt|grep -v '^[A-Z].*\+$'|grep -v '^[a-z].*\+$'|grep -v '^[0-9].*\+$'
!@#asdf
#$$$$$ [root@kevin ~]# cat a.txt |grep -v ^[a-Z]
2018 Good study 1wqe
2018stuDY is heht6ttt
!@#asdf
#$$$$$ [root@kevin ~]# cat a.txt |grep -v ^[a-Z]|grep -v [0-9]
!@#asdf
#$$$$$ grep获取多个条件(grep -E "条件1|条件2|条件3")
[root@kevin ~]# cat a.txt |grep -E "^[a-z]|^[0-9]"
good Study 2018hehehehe
2018 Good study 1wqe
2018stuDY is heht6ttt
anhui 2018asdfjlsadfdsaff grep过滤多个条件(grep -v "条件1\|条件2\|条件3"),注意""里面有转义符"\"
[root@kevin ~]# cat a.txt |grep -v "^[a-z]\|^[0-9]"
Good study 2018! hahahah~
!@#asdf
TOOk213gg asdfasdf
#$$$$$ [root@kevin ~]# cat a.txt |grep -v "[a-z]\|^[0-9]"
#$$$$$
10)删除字符串中指定字符(tr命令、sed命令)
一、使用sed将字符串中指定的字符删除
[root@kevin ~]# echo "2018-10-08 15:19:05"|sed 's/-//g'|sed 's#:##g'
20181008 151905 删除字符串中的特殊字符
[root@kevin ~]# cat test.sh
#!/bin/bash
str="root!@#QWE123"
echo ${str}| sed 's/\!//g' | sed 's/\@//g' | sed 's/\#//g' [root@kevin ~]# sh test.sh
rootQWE123 还可以使用tr -d命令进行删除:
[root@kevin ~]# cat test.sh
#!/bin/bash
str="root!@#QWE123"
echo ${str}| tr -d "!" | tr -d "@" | tr -d "#" [root@kevin ~]# sh test.sh
rootQWE123 -------------------------------------------------------------------------------
另外:sed也支持正则
sed -n '/[0-9]/p' filename 将文件中匹配数字的行打印出来
sed -n '/[a-z]/p' filename 将文件中匹配小写字母的行打印出来
sed -n '/[A-Z]/p' filename 将文件中匹配大写字母的行打印出来 sed -i '/[0-9]/d' filename 将文件中匹配数字的行删除
sed -n '/[a-z]/d' filename 将文件中匹配小写字母的行删除
sed -n '/[A-Z]/d' filename 将文件中匹配大写字母的行删除 sed -i '/[0-9]/s/root/huoqiu/g' filename 将文件中匹配数字的行里的root替换为huoqiu
sed -i '/[a-z]/s/root/huoqiu/g' filename 将文件中匹配小写字母的行里的root替换为huoqiu
sed -i '/[A-Z]/s/root/huoqiu/g' filename 将文件中匹配大写字母的行里的root替换为huoqiu ===============================================================================================
二、使用tr命令删除字符串中指定字符。tr使用-d参数可以起到删除字符的效果。支持正则表达式
[root@kevin ~]# echo "huoqiu123GOOD"|tr -d "a-z" #删除字符串中的小写字母
123GOOD
[root@kevin ~]# echo "huoqiu123GOOD"|tr -d "a-zA-Z" #删除字符串中的大写字母
123
[root@kevin ~]# echo "huoqiu123GOOD"|tr -d "0-9" #删除字符串中的数字
huoqiuGOOD 删除字符串中指定的部分字符
[root@kevin ~]# echo "huoqiu123GOOD"|tr -d "k"|tr -d "G"
evin123OOD
[root@kevin ~]# echo "huoqiu123GOOD"|tr -d "123"
huoqiuGOOD 截取字符串中的特殊字符
[root@kevin ~]# cat test.sh
#!/bin/bash
str="root!@#QWE123"
echo ${str}| tr -d "a-z"| tr -d "A-Z"| tr -d "0-9" [root@kevin ~]# sh test.sh
!@# 3)这里简单介绍下tr命令的日常用法
tr命令可以对来自标准输入的字符进行替换、压缩和删除。它可以将一组字符变成另一组字符,经常用来编写优美的单行命令,作用很强大。 语法
# tr (选项) (参数) 选项
-c或——complerment: 用字符集1中的字符串替换,要求字符集为ASCII。
-d或——delete: 删除所有属于字符集1的字符;
-s或--squeeze-repeats: 把连续重复的字符以单独一个字符表示。即压缩字符,但是必须是连续重复的单个字符!
-t或--truncate-set1: 先删除字符集1较字符集2多出的字符。 参数
字符集1:指定要转换或删除的原字符集。当执行转换操作时,必须使用参数“字符集2”指定转换的目标字符集。但执行删除操作时,不需要参数“字符集2”;
字符集2:指定要转换成的目标字符集。 tr用来从标准输入中通过替换或删除操作进行字符转换。
tr主要用于删除文件中控制字符或进行字符转换。
使用tr时要转换两个字符串:字符串1用于查询,字符串2用于处理各种转换。
tr刚执行时,字符串1中的字符被映射到字符串2中的字符,然后转换操作开始。 通过使用tr可以非常容易地实现sed的许多最基本功能,可以将tr看作为sed的(极其)简化的变体。
它可以用一个字符来替换另一个字符,或者可以完全除去一些字符。您也可以用它来除去重复字符。这就是所有 tr 所能够做的。 看看下面示例:
1)tr的替换命令
将输入字符由小写转换为大写:
[root@kevin ~]# echo "anhui@root"|tr "a-z" "A-Z"
ANHUI@ROOT 将输入字符由大写转换为小写:
[root@kevin ~]# echo "ANhui@ROOT"|tr "A-Z" "a-z"
anhui@root [root@kevin ~]# echo "172.16.60.34 data-node01"|tr "." "_"
172_16_60_34 data-node01
[root@kevin ~]# echo "root \n 213"| tr " " "#"
root#\n#213 [root@kevin ~]# echo "123456@abc"|tr "0-9" "#"
######@abc
[root@kevin ~]# echo "123456@abc"|tr "123" "pas" # 替换两个字符集的时候,分别是一个字符对应一个字符的关系
pas456@abc [root@kevin ~]# echo "123456@abc"|tr "123" "password" # 当字符集1的字符数少于字符集2的字符数时,就取字符集2的前面对应数目的字符进行替换
pas456@abc
[root@kevin ~]# echo "123456@abc"|tr "1234" "password"
pass56@abc
[root@kevin ~]# echo "123456@abc"|tr "12345" "password"
passw6@abc
[root@kevin ~]# echo "123456@abc"|tr "123456" "password"
passwo@abc [root@kevin ~]# echo "123456@abc"|tr "123456" "T" #当字符集1的字符数多于字符集2的字符数时,先进行两个字符集对应数目字符的替换,剩下多余的字符集1字符就使用字符集2的最后一个字符进行重复替换
TTTTTT@abc
[root@kevin ~]# echo "123456@abc"|tr "123456" "TM"
TMMMMM@abc
[root@kevin ~]# echo "123456@abc"|tr "123456" "TMC"
TMCCCC@abc
[root@kevin ~]# echo "123456@abc"|tr "123456" "TMCH"
TMCHHH@abc
[root@kevin ~]# echo "123456@abc"|tr "123456" "TMCHR"
TMCHRR@abc
[root@kevin ~]# echo "123456@abc"|tr "123456" "TMCHRY"
TMCHRY@abc 需要注意:
'A-Z' 和 'a-z'都是集合,集合是可以自己制定的,例如:'ABD-}'、'bB.,'、'a-de-h'、'a-c0-9'都属于集合,集合里可以使用'\n'、'\t',可以可以使用其他ASCII字符。
替换两个字符集的时候,分别是一个字符对应一个字符的关系
当字符集1的字符数少于字符集2的字符数时,就取字符集2的前面对应数目的字符进行替换
当字符集1的字符数多于字符集2的字符数时,先进行两个字符集对应数目字符的替换,剩下多余的字符集1字符就使用字符集2的最后一个字符进行重复替换 另外:"O*n" 表示字符O重复出现指定次数n。因此"O*2"匹配OO的字符串!!!!
[root@kevin ~]# echo "aaa123"|tr "a*3" "w" #将a和3都替换为了w
www12w
[root@kevin ~]# echo "aaa123"|tr "a*3" "xy" #将a替换为了x,3替换为了y
xxx12y
[root@kevin ~]# echo "aaa123"|tr "a3" "xy"
xxx12y
[root@kevin ~]# echo "aaaaaaaa123"|tr "a*3" "xyz"
xxxxxxxx12z [root@kevin ~]# echo "aaa123"|tr "aaa" "w" #匹配字符集1中最后一个字符对应字符集2中的那个字符
www123
[root@kevin ~]# echo "aaa123"|tr "aaa" "wx"
xxx123
[root@kevin ~]# echo "aaa123"|tr "aaa" "wxy"
yyy123
[root@kevin ~]# echo "aaa123"|tr "aaa" "wxym"
yyy123
[root@kevin ~]# echo "aaa123"|tr "aaa" "wxymn"
yyy123 2)tr的删除命令 (上面案例已经说明)
[root@kevin ~]# echo "hello 123 world 456" | tr -d '0-9'
hello world [root@kevin ~]# cat test
beijing
shanghai
abcde
[root@kevin ~]# cat test|tr -d "abcji" #即凡是test文件中出现的a,b,c,j,i都会被删除
eng
shngh
de 3)用tr压缩字符,可以压缩输入中重复的字符。但是注意:必须是连续重复的单个字符!!
[root@kevin ~]# echo "thissss is a text linnnnnnne." | tr -s ' sn'
this is a text line.
[root@kevin ~]# echo "123123123"|tr -s "123"
123123123
[root@kevin ~]# echo "123333344444"|tr -s "3"|tr -s "4"
1234 4)巧妙使用tr命令进行数字相加操作:
[root@kevin ~]# echo 1 2 3 4 5 6 7 8 9 | xargs -n1 | echo $[ $(tr '\n' '+') 0 ]
45
[root@kevin ~]# echo "10 11 12 13 14"|xargs -n1|echo $[ $(tr '\n' '+') 0 ]
60 --------------------------------------------------------------------------------------
<<<<< "xargs -n[数字]"用法 >>>>>
[root@kevin ~]# echo "aa bb cc 1 2 3"|xargs
aa bb cc 1 2 3
[root@kevin ~]# echo "aa bb cc 1 2 3"|xargs -n1
aa
bb
cc
1
2
3
[root@kevin ~]# echo "aa bb cc 1 2 3"|xargs -n2
aa bb
cc 1
2 3
[root@kevin ~]# echo "aa bb cc 1 2 3"|xargs -n3
aa bb cc
1 2 3
[root@kevin ~]# echo "aa bb cc 1 2 3"|xargs -n4
aa bb cc 1
2 3
-------------------------------------------------------------------------------------- 5)把文件中的数字0-9替换为a-j (都是10个字符,一一对应)
[root@kevin ~]# cat filename |tr [0-9] [a-j] 6)删除文件file中出现的换行'\n'、制表'\t'字符
[root@kevin ~]# cat filename | tr -d "\n\t" 删除换行符等
[root@kevin ~]# echo -e "asdf\n123"|tr -d "\n"
asdf123
[root@kevin ~]# echo -e "asdf\n\r\t123"|tr -d "\n\r\t"
asdf123 7)删除空行
[root@kevin ~]# cat file | tr -s "\n" > new_file [root@kevin ~]# cat test
beijing
shanghai abcde 123123
[root@kevin ~]# cat test| tr -s "\n"
beijing
shanghai
abcde
123123 8)把路径变量中的冒号":",替换成换行符"\n"
[root@kevin ~]# echo "a:b:c:d"|tr ":" "\n"
a
b
c
d [root@kevin ~]# echo "/www/data/haha/html"|tr "/" ":"
:www:data:haha:html 9)字符集补集!!! (tr -d -c)
set1的补集意味着从这个集合中包含set1中没有的所有字符。
最典型的用法就是从输入文本中将不在补集中的所有字符全部删除!!!!
[root@kevin ~]# echo "hello 123 world " | tr -d -c '0-9 \n'
123
[root@kevin ~]# echo "wang beijinganhui"|tr -d -c 'a-m\n'
agbeijigahi
[root@kevin ~]# echo "123WRsdf"|tr -d -c "a-z\n"
sdf
[root@kevin ~]# echo "123@#QWEanhui"|tr -d -c "anhui\n"
anhui 10) 删除Windows文件"造成"的'^M'字符
[root@kevin ~]# cat file | tr -s "\r" "\n" > new_file
或
[root@kevin ~]# cat file | tr -d "\r" > new_file 11) 使用tr命令生成固定长度的随机密码!!!!
[root@kevin ~]# head /dev/urandom | tr -dc A-Za-z0-9 | head -c 20
koR3ZjLekd6Xujfeslu1
[root@kevin ~]# head /dev/urandom | tr -dc A-Za-z0-9 | head -c 20
vgOKX39zeQSWP6KD6rjd
[root@kevin ~]#
11)shell的 read 输入用法
read命令用于接收键盘或其它文件描述符的输入。
read命令接收标准输入(键盘)的输入,或其他文件描述符的输入(后面在说)。得到输入后,read命令将数据放入一个标准变量中。
read 命令格式如下:
#read [选项] [变量名] 选项:
-p: 指定要显示的提示
-s: 静默输入,输入的数据不显示出来。实际上输入数据是显示的,只是read命令将文本颜色设置成与背景相同的颜色!!!一般用于密码输入。
-n: 指定输入的字符长度最大值。如果超出了,就默认使用前面最大长度值的字符!
-d '字符': 输入结束符,当你输入的内容出现这个字符时,立即结束输入
-t N: 超出N秒没有进行输入,则自动退出。 需要注意:
变量名可以自定义。如果不指定变量名,则会把输入保存到默认变量REPLY中;
如果只提供了一个变量名,则将整个输入行赋予该变量;
如果提供了一个以上的变量名,则输入行分为若干字,一个接一个地赋予各个变量,而命令行上的最后一个变量取得剩余的所有字; [root@kevin ~]# read -p "请输入你的内容: " haha;echo "${haha}"
请输入你的内容: 123456
123456 加了-s参数,即静默输入。输入数据的时候看不到。默认不换行!
[root@kevin ~]# read -sp "请输入你的内容: " haha;echo "${haha}"
请输入你的内容: 123456 [root@kevin ~]# read -sp "请输入你的内容: " haha;echo -e "\n${haha}"
请输入你的内容:
123456 下面来看看下面的一些示例:
1)基本读取
[root@kevin ~]# cat test.sh
#!/bin/bash
echo -n "Enter your name:" #参数-n的作用是不换行,echo默认是换行!
read name #从键盘输入
echo "hello $name,welcome to my program" #显示信息
exit 0 #退出shell程序。 [root@kevin ~]# sh test.sh
Enter your name:beijing
hello beijing,welcome to my program 2)使用read输入 (read -p)
由于read命令提供了-p参数,允许在read命令行中直接指定一个提示。
上面脚本可以改进为:
[注意:read命令后必须加它自己的参数,如果不加参数,则不执行!]
[root@kevin ~]# cat test.sh
#!/bin/bash
read -p "Enter your name:" name
echo "hello $name, welcome to my program"
exit 0 [root@kevin ~]# sh test.sh
Enter your name:beijing
hello beijing, welcome to my program 需要注意:
在上面read后面的变量只有name一个,也可以有多个,多个变量使用空格隔开,这时如果输入多个数据,则第一个数据给第一个变量,第二个数据给第二个变量;
如果输入数据个数过多,则最后所有的值都给最后那个变量!!
如果输入数据太少,则对应不到数据的变量为空!
在read命令行中也可以不指定变量,如果不指定变量,那么read命令会将接收到的数据放置在环境变量REPLY中。 3)read后面可以跟多个变量
[root@kevin ~]# cat test.sh
#!/bin/bash
read -p "Enter your name:" name age city
echo "hello ${name},${age},${city}, welcome to my program"
exit 0 [root@kevin ~]# sh test.sh
Enter your name:bobo 26 beijing
hello bobo,26,beijing, welcome to my program 如果输入数据多余变量,则多余的数据都给最后那个变量!!
[root@kevin ~]# sh test.sh
Enter your name:yang 26 shanghai huoqiu haha
hello yang,26,shanghai huoqiu haha, welcome to my program 如果输入数据少于变量,则对应不到数据的变量为空!
[root@kevin ~]# sh test.sh
Enter your name:yang 26
hello yang,26,, welcome to my program [root@kevin ~]# sh test.sh
Enter your name:yui
hello yui,,, welcome to my program 4)不跟变量,默认使用${REPLY}
如果read后面不指定变量,则read命令会将接收到的数据放置在环境变量REPLY中!!!!
环境变量REPLY中包含输入的所有数据,可以像使用其他变量一样在shell脚本中使用环境变量REPLY,即${REPLY}
[root@kevin ~]# cat test.sh
#!/bin/bash
read -p "Enter your name:"
echo "${REPLY}是输入的内容"
exit 0 [root@kevin ~]# sh test.sh
Enter your name:zhangyang is 27,very nice!!
zhangyang is 27,very nice!!是输入的内容 5)read的计时输入 (read -t)
使用read命令存在着潜在危险,脚本很可能会停下来一直等待用户的输入。
如果无论是否输入数据脚本都必须继续执行,那么可以使用-t选项指定一个计时器。
-t选项指定read命令等待输入的秒数。当计时满时,read命令返回一个非零退出状态;
[root@kevin ~]# cat test.sh
#!/bin/bash
if read -t 5 -p "please enter your name:" name
then
echo "hello $name ,welcome to my script"
else
echo "sorry,too slow"
fi
exit 0 [root@kevin ~]# sh test.sh
please enter your name:zhangtianba
hello zhangtianba ,welcome to my script [root@kevin ~]# sh test.sh
please enter your name:sorry,too slow 即超出5s没有输入内容,脚本就自动结束! 6)read的计算字符长度输入 (read -n)
除了输入时间计时,还可以设置read命令计数输入的字符。当输入的字符数目达到预定数目时,自动退出,并将输入的数据赋值给变量。
[root@kevin ~]# cat test.sh
#!/bin/bash
read -n1 -p "Do you want to continue [Y/N]?" answer
case $answer in
Y | y)
echo -e "\nfine ,continue";;
N | n)
echo -e "\nok,good bye";;
*)
echo -e "\nerror choice";;
esac
exit 0 [root@kevin ~]# sh test.sh
Do you want to continue [Y/N]?y
fine ,continue [root@kevin ~]# sh test.sh
Do you want to continue [Y/N]?N
ok,good bye [root@kevin ~]# sh test.sh
Do you want to continue [Y/N]?A
error choice 注意:
该例子使用了-n选项,后接数值1,指示read命令只要接受到一个字符就退出。
只要按下一个字符进行回答,read命令立即接受输入并将其传给变量。无需按回车键。
上面脚本中要在echo语句中添加换行符"\n",否则执行脚本,在输入内容后会将echo的内容和read提示信息放在一行!
echo需要加上参数"-e"才能将后面引号内的特殊字符"\n"生效!否则就当普通字符处理了! 如果输入的字符超过了设定的最大字符长度,则就默认使用前面最大长度值的字符!
[root@kevin ~]# cat test.sh
#!/bin/bash
read -n5 -p "please input name:" name
echo "需要输入的名字是:${name}" 没有超过设定的最大字符长度,这时候会自动换行!
[root@kevin ~]# sh test.sh
please input name:bao
需要输入的名字是:bao 超过了设定的最大字符长度。
本来输入的是zhangzihua,但是默认使用了前面5个字符:zhang
超过后,不会自动换行!
[root@kevin ~]# sh test.sh
please input name:zhang需要输入的名字是:zhang 改进下,解决不换行问题:
[root@kevin ~]# cat test.sh
#!/bin/bash
read -n5 -p "please input name:" name
echo -e "\n需要输入的名字是:${name}" 这样,输入字符超过设定的最大字符长度时,就会自动换行了!
[root@kevin ~]# sh test.sh
please input name:zhang
需要输入的名字是:zhang 再来改进下脚本:
[root@kevin ~]# cat test.sh
#!/bin/bash
read -n5 -p "please input name:" name len=$(expr length "${name}")
#或者使用len=`echo ${#name}`
if [ ${len} -lt 5 ];then #注意第一个逻辑判断中的len变量不能等于设置的最大长度值,否则下面就不会执行。
echo "输入的名字为:${name}" #当不超过设定的字符长度时,会自动换行
else
echo -e "\n输入的名字长度超过5,当前名字为${name}"
exit 0
fi [root@kevin ~]# sh test.sh
please input name:bao
输入的名字为:bao [root@kevin ~]# sh test.sh
please input name:hangu
输入的名字长度超过5,当前名字为hangu 7)read的静默输入。(read -s)
有时会需要脚本用户输入,但不希望输入的数据显示在监视器上。典型的例子就是输入密码,当然还有很多其他需要隐藏的数据。
-s选项能够使read命令中输入的数据不显示在监视器上(实际上,数据是显示的,只是read命令将文本颜色设置成与背景相同的颜色!!!)。
[root@kevin ~]# cat test.sh
#!/bin/bash
read -s -p "Enter your password: " pass
echo -e "\nyour password is $pass"
exit 0 静默输入,即输入的数据是看不到的。
[root@kevin ~]# sh test.sh
Enter your password:
your password is 123456 8)read读取文件!!!!(cat filename | while read line)
可以使用read命令读取Linux系统上的文件。
每次调用read命令都会读取文件中的"一行"文本!!
当文件没有可读的行时,read命令将以非零状态退出。
读取文件的关键是如何将文本中的数据传送给read命令?? 最常用的方法:对文件使用cat命令并通过管道将结果直接传送给包含read命令的while命令 [root@kevin ~]# cat test.txt
wangbo is a boy!
beijing is good!
abc 123 sahdfksfah
asf#$$!QA [root@kevin ~]# cat test.sh
#!/bin/bash
count=1
cat test.txt | while read line #cat命令的输出作为read命令的输入,read读到的值放在line中。line为读取文件行内容的变量
do
echo ${line}|grep -w "beijing" >/dev/null 2>&1
if [ $? -eq 0 ];then
echo "想要的是:${line}"
else
echo "Line ${count}:${line}" #读取的内容默认为变量${line}
count=$[ ${count} + 1 ] #注意中括号中的空格。
fi
done
echo "finish"
exit 0 [root@kevin ~]# sh test.sh
Line 1:wangbo is a boy!
想要的是:beijing is good!
Line 2:abc 123 sahdfksfah
Line 3:asf#$$!QA
finish
12)shell的 case 用法
case语句还是很好理解的,在shell编程中,if语句有它的语法,函数也有它的语法,那么在shell编程中的case语句也是有它的语法的,语法格式如下: case ${变量名} in
赋值1)
执行指令1
;; # 每一个选择都以双;;结束。(需要注意:;;相当于break语句)
赋值2)
执行指令2
;;
赋值3)
执行指令3
;;
*) # *未匹配到相符的其他值
执行其他指令
;;
esac 示例一
当命令行参数是 1 时,输出 "周一", 是 2 时,就输出"周二", 其它情况输出 "其他"
---------------------------------------------------------------------
[root@localhost ~]# cat test.sh
#!/bin/bash
case $1 in
1)
echo "周一"
;;
2)
echo "周二"
;;
*)
echo "其他"
;;
esac [root@localhost ~]# sh test.sh 1
周一
[root@localhost ~]# sh test.sh 2
周二
[root@localhost ~]# sh test.sh 3
其他
[root@localhost ~]# sh test.sh 4
其他
[root@localhost ~]# sh test.sh
其他 示例二
shell脚本中case选择语句可以结合read指令实现比较好的交互应答操作,case接收到read指令传入的一个或多个参数,然后case根据参数做选择操作。
---------------------------------------------------------------------
1) 案例1
[root@localhost ~]# cat test.sh
#!/bin/bash
echo "Please enter A,B,C"
read letter
#上面两句可以改进为:
#read -p "Please enter A,B,C: " letter
case $letter in
A|a)
echo "you entered A"
;;
B|b)
echo "you entered B"
;;
C|c)
echo "you entered C"
;;
*)
echo "Not in A,B,C"
;;
esac
[root@localhost ~]# sh test.sh
Please enter A,B,C
A
you entered A
[root@localhost ~]# sh test.sh
Please enter A,B,C
b
you entered B
[root@localhost ~]# sh test.sh
Please enter A,B,C
C
you entered C
[root@localhost ~]# sh test.sh
Please enter A,B,C
w3
Not in A,B,C
[root@localhost ~]# sh test.sh 2) 案例二:查看系统资源使用情况
[root@localhost ~]# cat test.sh
#!/bin/bash
echo "check system run status"
echo "show CPUinfo: C/c "
echo "show Memery used: M/m "
echo "show Disk use status: D/n "
echo "show System user login: U/n "
echo "show System load average:L/l"
echo "show System Ip address: I/i" read_input () {
read -t 10 -p "please Input C/M/D/U/L/I : " char
}
show_status () {
case $char in
C | c )
cat /proc/cpuinfo | grep -o -i 'model name.*'
;;
M | m )
free -m
;;
D | d )
df -h
;;
U | u )
w
;;
L | l )
top | head -1 | cut -d " " -f 11-15
;;
I | i )
ifconfig | grep -o "[0-9.]\{7,\}" | head -1
;;
* )
echo "The characters you have entered are wrong. Please look at the hints"
;;
esac
} for i in $( seq 1 10) #呼应前面"read -t 10"中的10秒钟要输入内容的限制
do
read_input
show_status
if [ $i -eq 10 ]; then
echo "已经到达查询的最大次数,脚本退出;"
fi
done [root@localhost ~]# sh test.sh
check system run status
show CPUinfo: C/c
show Memery used: M/m
show Disk use status: D/n
show System user login: U/n
show System load average:L/l
show System Ip address: I/i
please Input C/M/D/U/L/I : c
model name : Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.40GHz
model name : Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.40GHz
model name : Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.40GHz
model name : Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.40GHz
please Input C/M/D/U/L/I : m
total used free shared buff/cache available
Mem: 7815 250 5826 56 1738 5102
Swap: 2047 0 2047
please Input C/M/D/U/L/I : d
Filesystem Size Used Avail Use% Mounted on
devtmpfs 3.9G 0 3.9G 0% /dev
tmpfs 3.9G 0 3.9G 0% /dev/shm
tmpfs 3.9G 57M 3.8G 2% /run
tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
/dev/mapper/centos-root 20G 3.2G 17G 16% /
/dev/mapper/centos-data 78G 33M 78G 1% /data
/dev/xvda1 197M 166M 32M 85% /boot
tmpfs 782M 0 782M 0% /run/user/0
please Input C/M/D/U/L/I : u
11:07:27 up 31 days, 17:24, 2 users, load average: 0.00, 0.01, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root tty1 30Oct19 31days 0.03s 0.03s -bash
root pts/0 172.16.198.22 09:57 7.00s 0.18s 0.00s w
please Input C/M/D/U/L/I : l
load average: 0.00, 0.01,
please Input C/M/D/U/L/I : i
172.16.60.236
please Input C/M/D/U/L/I : a
The characters you have entered are wrong. Please look at the hints
please Input C/M/D/U/L/I : The characters you have entered are wrong. Please look at the hints
please Input C/M/D/U/L/I : The characters you have entered are wrong. Please look at the hints
please Input C/M/D/U/L/I : The characters you have entered are wrong. Please look at the hints
已经到达查询的最大次数,脚本退出; 案例3:
有时经常会使用比较长的if,then,else来尝试计算一个变量的值,在一组可能的值中寻找特定值。其实这种情况如果使用case遇见就会变得简单的多了!
使用多个if判断来一一核对,代码量比较多,还容易乱。用case的话,能减少代码量,不需要再写出所有的elif语句来不停地检查同一个变量的值了。case命
令会采用列表格式来检查单个变量的多个值。如下两种方法效果一样: if判断语句写法:
[root@localhost ~]# cat test.sh
#!/bin/bash USER=$1
if [ $USER = "kevin" ];then
echo "Welcome $USER,Please enjoy your visit"
elif [ $USER = "grace" ];then
echo "Welcome $USER,Please enjoy your visit"
elif [ $USER = "xiaoru" ];then
echo "Special testing account"
elif [ $USER = "shibo" ];then
echo "Do not forget to logout when you're done"
else
echo "Sorry, you are not allowed here"
fi case语句写法:
[root@localhost ~]# cat test.sh
#!/bin/bash USER=$1
case ${USER} in
kevin|grace)
echo "Welcome $USER,Please enjoy your visit";;
xiaoru)
echo "Special testing account";;
shibo)
echo "Do not forget to logout when you're done";;
*)
echo "Sorry, you are not allowed here";;
esac 示例三:
case语句经常会使用在应用服务的一键部署脚本中。
比如:https://www.cnblogs.com/kevingrace/p/6086426.html
--------------------------------------------------------------------- 示例四:
结合shell的"function函数+if逻辑判断+case选择语句
---------------------------------------------------------------------
[root@localhost ~]# cat test.sh
#!/bin/bash function OPS(){ #定义一个OPS的函数
cat << kevin_test
1.北京
2.上海
3.深圳
kevin_test
}
OPS #调用CDAN函数
read -p "请输入您想要去的地方: " WHERE #输入一条提示,然后把用户输入的字符串赋值给变量WHERE
expr ${WHERE} + 1 >/dev/null 2>&1 #使用数值运算命令expr来确定用户输入的是否是数值
if [ "$?" -ne 0 ];then #如果用户输入的不是数值
echo "请您输入{1|2|3}"
exit 1
fi case ${WHERE} in
1)
echo "明天去北京!"
;;
2)
echo "明天去上海!"
;;
3)
echo "明天去深圳!"
;;
esac [root@localhost ~]# sh test.sh
1.北京
2.上海
3.深圳
请输入您想要去的地方: 1
明天去北京! 示例五:
再来分享一例shell的case循环用法
---------------------------------------------------------------------
要求:
输入a|A显示出红色的本机IP
输入b|B显示出绿色的本机磁盘的剩余内存
输入c|C显示出黄色的系统运行时间
输入 q|Q显示出蓝色的直接退出 [root@localhost ~]# cat test.sh
#!/bin/bash
while true
do
echo -e "
\033[31m A 显示主机ip \033[0m
\033[32m B 显示磁盘剩余空间 \033[0m
\033[33m C 显示系统运行时间 \033[0m
\033[34m Q 退出系统 \033[0m
"
read -p "请输入你的选择:" char
case ${char} in
a|A)
echo -e "\033[31m `ifconfig eth0 | grep "netmask" | awk '{print $2}'` \033[0m"
;;
b|B)
echo -e "\033[32m `df -h | awk 'NR==2{print "剩余空间大小为:"$4}'` \033[0m"
;;
c|C)
echo -e "\033[33m `uptime | awk '{print "系统已经运行了"$3""$4""}'` \033[0m"
;;
q|Q)
exit 0
;;
*)
echo "请输入A/B/C/Q"
;;
esac
done [root@localhost ~]# sh test.sh A 显示主机ip
B 显示磁盘剩余空间
C 显示系统运行时间
Q 退出系统 请输入你的选择:a
172.16.60.238 A 显示主机ip
B 显示磁盘剩余空间
C 显示系统运行时间
Q 退出系统 请输入你的选择:b
剩余空间大小为:3.9G A 显示主机ip
B 显示磁盘剩余空间
C 显示系统运行时间
Q 退出系统 请输入你的选择:c
系统已经运行了32days, A 显示主机ip
B 显示磁盘剩余空间
C 显示系统运行时间
Q 退出系统 请输入你的选择:d
请输入A/B/C/Q A 显示主机ip
B 显示磁盘剩余空间
C 显示系统运行时间
Q 退出系统 请输入你的选择:q
[root@localhost ~]#
12)Shell的 for、case、while 循环流程控制语句用法
shell作为一种脚本编程语言,同样包含循环、分支等其他程序控制结构,从而轻松完成更加复杂、强大的功能。
编写脚本的思路
1. 明确脚本的功能
2. 编写脚本时会使用到那些命令
3. 把变化的数据使用变量表示
4. 选择适合的流程控制 (选择 、 循环 、分支) 一、使用for循环语句
========================================================================================================
在工作中,经常遇到某项任务需要多次执行,而每次执行仅仅是处理对象不一样,其他命令都相同。使用简单的if语句已经难以满足要求,
编写全部代码将困难重重,而for循环语句将很好的解决类似的问题。 for语句的结构
使用for循环语句时,需要指定一个变量及可能的取值列表,针对每一个不同的取值重复执行相同的命令,直到变量值用完退出循环。 for的语法结构:
for;do;done 语法格式:
for 变量名 in 列表内容
do
commands
done 或者
for 变量名 in 列表内容 ;do
commands
done 示例1):使用嵌套循环输出99乘法表
[root@localhost ~]# cat test.sh
#!/bin/bash
for i in `seq 9`
do
for j in `seq 9`
do
[ $j -le $i ] && echo -n "$j x $i = `echo $(($j*$i))` " #如果j 小与等于i才会打印式子。注意后面双引号后面要有一个空格,表示下面执行时各列间的空格。
done
echo ""
done 注意:外层循环循环行,内层循环循环列。$(())返回的是里面运算结果;echo -n表示不换行
规律: 内层循环的变量<=外层循环的变量 [root@localhost ~]# sh test.sh
1 x 1 = 1
2 x 1 = 2 2 x 2 = 4
3 x 1 = 3 3 x 2 = 6 3 x 3 = 9
4 x 1 = 4 4 x 2 = 8 4 x 3 = 12 4 x 4 = 16
5 x 1 = 5 5 x 2 = 10 5 x 3 = 15 5 x 4 = 20 5 x 5 = 25
6 x 1 = 6 6 x 2 = 12 6 x 3 = 18 6 x 4 = 24 6 x 5 = 30 6 x 6 = 36
7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 7 x 4 = 28 7 x 5 = 35 7 x 6 = 42 7 x 7 = 49
8 x 1 = 8 8 x 2 = 16 8 x 3 = 24 8 x 4 = 32 8 x 5 = 40 8 x 6 = 48 8 x 7 = 56 8 x 8 = 64
9 x 1 = 9 9 x 2 = 18 9 x 3 = 27 9 x 4 = 36 9 x 5 = 45 9 x 6 = 54 9 x 7 = 63 9 x 8 = 72 9 x 9 = 81 示例2):根据IP地址检查主机状态
[root@localhost ~]# vim test.sh
#!/bin/bash
for NUM in $(seq 1 254) #或者直接"seq 254" 或者 "seq 10 30"用于一段ip
do
IP=172.16.60.${NUM}
# -c表示ping的次数,-i表示时间间隔(秒),
ping -c 3 -i 0.2 $IP &> /dev/null
if [ $? -eq 0 ];then
echo "$IP is up"
else
echo "$IP id down"
fi
done 示例3):文件列表循环
[root@localhost ~]# vim test.sh
#!/bin/bash
cd /etc/
for a in `ls /etc/`
do
if [ -d $a ]
then
ls -d $a
fi
done 二、使用while循环语句
========================================================================================================
for语句适用于列表对象无规律,且列表来源以固定的场合。而对于要求控制循环次数、操作对象按数字顺序编号、按特定的条件重复操作等情况,则更适合于while循环语句。
while循环:重复测试某个条件,只要条件成立,就重复执行命令,条件不成立,立即退出,自带判断; while语句的结构
使用while循环语句时,可以根据特定的条件反复执行一个命令序列,直到该条件不在满足为止。
需要注意:要避免出现while ture 的死循环!!! 语法格式如下:
while 测试命令
do
命令
done 退出while循环体的三种方式:
1. 条件为假退出循环体,继续执行循环体以外的命令;
2. exit退出脚本,循环体外的命令不会执行;
3. break退出脚本中的循环体,继续执行循环体外的命令; 特殊条件表达式:
1. true :当条件表达式为true时,那么代表条件表达式永远成立,为真;
2. false:当条件表达式为false时,那么条件表达式永远为假; 示例1):降序输出10到1
[root@localhost ~]# cat test.sh
#!/bin/bash
num=10
while [ ${num} -gt 0 ]
do
echo "${num}"
num=$[${num}-1]
#或者使用下面的表达式也可以,$(())或$[]都表示返回运算结果
num=$((${num}-1))
done
[root@localhost ~]# sh test.sh
10
9
8
7
6
5
4
3
2
1 示例2):批量添加用户
用户名称以kevin_开头,按照数字顺序进行编号
添加10个用户,即kevin_1、kevin_2、...、kevin_10
初始密码均设为123456
[root@VM_16_9_centos ~]# cat test.sh
#!/bin/bash
UR="kevin_"
NUM=1
while [ ${NUM} -le 10 ]
do
USER=${UR}${NUM}
useradd ${USER}
echo "123456"|passwd --stdin ${USER}
NUM=$((${NUM}+1))
#或者使用let NUM++,效果等同于NUM=$((${NUM}+1))或者NUM=$[${NUM}+1]
done 示例3)判断输入的数要是数字
[root@ss-server ~]# cat test.sh
#!/bin/bash
while :
do
read -p "Please input a number: " n
if [ -z "$n" ];then #空串为真
echo "you need input sth."
continue
fi
n1=`echo $n|sed 's/[0-9]//g'`
if [ -n "$n1" ];then #非空串为真
echo "you just only input numbers."
continue
fi
break
done
echo $n [root@ss-server ~]# sh test.sh
Please input a number: 2
2
[root@ss-server ~]# sh test.sh
Please input a number: 2a
you just only input numbers.
Please input a number:
you need input sth.
Please input a number: 5
5 三、使用case分支语句
========================================================================================================
case语句主要适用于以下情况:
某个变量存在多种取值,需要对其中的每一种取值分别执行不同的命令序列。与多分支if语句相识,只是if语句需要判断多个不同的条件,而case只是判断一个变量的不同取值 1) case语句的结构如下:
case 变量或表达式 in
变量或表达式1)
命令序列1
;;
变量或表达式2)
命令序列2
;;
......
*)
默认命令序列
;;
esac 2) case执行流程
1. 首先使用"变量或表达式"的值与值1进行比较,若取值相同则执行值1后的命令序列,直到遇见双分号";;"后跳转至esac,表示分支结束;
2. 若与值1不相匹配,则继续与值2进行比较,若取值相同则执行值2后的命令序列,直到遇见双分号";;"后跳转至esac,表示结束分支;
3. 依次类推,若找不到任何匹配的值,则执行默认模式"*)"后的命令序列,直到遇见esac后结束分支。 3) case执行流程注意事项
1. "变量或表达式"后面必须为单词in,每一个"变量或表达式"的值必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至;;
2. 匹配中的值可以是多个值,通过"|"来分隔。
3. 匹配中的值可以是正则。 示例1):编写一个备份,拷贝的交互式脚本
[root@localhost ~]# cat test.sh
#!/bin/bash
cat <<eof
*****************
**1. backup
**2. copy
**3. quit
*****************
eof read -p "input your choose: " OP
case $OP in
1|backup)
echo "Backup..."
;;
2|copy)
echo "Copy..."
;;
3|quit)
exit
;;
*)
echo input error
esac
[root@localhost ~]# sh test.sh
*****************
**1. backup
**2. copy
**3. quit
*****************
input your choose: 1
Backup...
[root@localhost ~]# sh test.sh
*****************
**1. backup
**2. copy
**3. quit
*****************
input your choose: 2
Copy... 示例2):提示用户输入一个字符,判断出该字符是字母、数字
[root@localhost ~]# cat test.sh
#!/bin/bash
#read后面跟的变量必须要空格隔开,否则变量无效!
read -p "请输入一个字符: " star case ${star} in
[a-z]|[A-Z])
echo "输入的是一个字母"
;;
[0-9])
echo "输入的是一个数字"
;;
*)
echo "请输入字母或数字"
;;
esac [root@localhost ~]# sh test.sh
请输入一个字符: a
输入的是一个字母
[root@localhost ~]# sh test.sh
请输入一个字符: 3
输入的是一个数字
13)Shell的 function 函数用法
简单的说,Shell函数的作用就是将程序里面多次被调用的代码组合起来,称为函数体,并取一个名字称为(函数名),当需要用到这段代码的时候,就可以直接来调用函数名。 Shell函数是一个脚本代码块,可以对它进行自定义命名,并且可以在脚本中任意位置使用这个函数。
如果想要这个函数,只要调用这个函数的名称就可以了。使用函数的好处在于模块化以及代码可读性强。 一、Shell函数的创建语法
================================================================================================
在shell中 if语句有它的语法,for循环也有它的语法,那么shell中的函数,那肯定也有它的语法有以下三种: 函数的创建方法一:
function 函数名 () {
指令...
return -n
} 函数的创建方法二:
function 函数名 {
指令...
return -n
} 函数的创建方法三:
函数名 () {
指令...
return -n
} 需要注意:
1. 在以上三种函数语法中,前面的funcation 表示声明一个函数! 可以不写 return -n 是指退出函数!
2. 上面最后两种函数创建方法的声明方式效果等价(即函数的创建方法二和函数的创建方法三的效果是一样的)!!!!!!!
3. 如果函数名后面没有跟(),则函数名和"{"之间必须有空格!shell对空格变态的敏感。如果函数名后面有(),则两者之间可以有空格,也可没有空格。
4. 不得声明形式参数。
5. 必须在调用前声明。
6. 无法重载。
7. 后来的声明会覆盖之前的声明。即如果存在相同名称的函数,以最后一个为准! 另外注意:函数名称在当前脚本必须唯一。 二、Shell函数调用的方法
================================================================================================
调用方法1:直接指定函数名即可。但一定要注意在声明之后才可以调用函数!!格式如下:
函数名称 调用方法2:调用函数时可以传递参数,函数内部中使用$1、$2......来引用传递的参数。格式如下:
函数名称 参数1 参数2 ...... 需要注意:
1. 其实函数被调用时会被当作一个小脚本来看待,调用时也可以在函数名后跟参数。
2. Shell函数在调用时都不可以加() $1 #调用第一个参数
$2 #调用第二个参数
...
$n #调用第n个参数
$# #返回参数个数n
$0 #当前脚本文件名 三、Shell函数的返回值
================================================================================================
Shell函数运行结束后会有一个退出状态码,可以用$?变量来显示上一条命令/函数执行结束的退出状态码。
当然,shell也为我们提供了return,像其他语言函数中return 一样,不过(整形)返回值必须在0~255之间。 四、Shell函数创建库
================================================================================================
与c的头文件类似,在Shell中,也可以定义"库文件",然后再另一个文件中导入。库文件没有特殊声明或者定义,也是脚本文件.sh。
使用库函数的关键在于导入库文件。用source来导入,source实际上会在当前shell上下文中执行命令,从而达到导入效果。
注意:使用"source"或点符号"."都可以导入库文件!(如下示例7) 五、在"~/.bashrc"文件中定义Shell函数
================================================================================================
在使用函数的库文件时,如果每次都需要自己去导入定义的库文件会显得很麻烦!那么,我们可不导入直接使用呢?答案是肯定可以的!!!
方法就是在Shell的配置文件的.bashrc中声明该函数,因为每次启动shell都会载入.bashrc文件,所以就实现了"自动导入库文件"!!!(如下示例8) 六、Shell函数使用实例
================================================================================================ 示例1:直接在调用函数时进行参数传递!可以直接传递具体的变量值!
[root@ss-server ~]# cat test.sh
#!/bin/bash function kevin(){
echo "welcome to anhui!"
} function shibo(){
echo "$1+$2"
} grace(){
echo $(($1+$2+$3))
} kevin
shibo hello world
grace 2 4 5
[root@ss-server ~]# sh test.sh
welcome to anhui!
hello+world
11 再看一例:调用函数时,也可以直接传递变量。在脚本执行的时候再赋予变量具体的值!
[root@ss-server ~]# cat test.sh
#!/bin/bash function kevin () {
echo "老子想要的是:$1 $2"
}
kevin $1 $2 [root@ss-server ~]# sh test.sh 房子 车子
老子想要的是:房子 车子 示例2:如果存在相同名称的函数,以最后一个为准!即后来的函数声明会覆盖之前的声明!
[root@ss-server ~]# cat test.sh
#!/bin/bash function kevin(){
echo "welcome to anhui!"
} kevin(){
echo "hello world"
} kevin
[root@ss-server ~]# sh test.sh
hello world 示例3:return返回值
使用return命令来退出函数并返回特定的退出码($?)
[root@ss-server ~]# cat test.sh
#!/bin/bash function kevin(){
echo "welcome to anhui!"
return 2
echo "why reruen"
} kevin [root@ss-server ~]# sh test.sh
welcome to anhui! 需要注意:
return一般是在函数的最后一行,因为一旦执行return命令,该函数后面的命令就不执行了。
return与exit的区别:return和exit都可以返回退出码,但是不同的是,return是退出函数,而exit是退出整个脚本。 示例4:函数值赋给变量
如下方实例中显示,此时的函数就相当于一个命令,需要使用$()或``调用。
[root@ss-server ~]# cat test.sh
#!/bin/bash function kevin(){
read -p "请输入内容: " str
echo ${str}
} bo=$(kevin) #也可以是bo=`kevin`
echo "测试结果为${bo}"
[root@ss-server ~]# sh test.sh
请输入内容: xinzhongguo
测试结果为xinzhongguo 示例5:外部参数传入函数
前面已经提到过,调用函数可以在后面跟随参数,函数内部可以使用$n的形式调用。
[root@ss-server ~]# cat test.sh
#!/bin/bash function kevin_1(){
echo "this is $1"
} function kevin_2 {
echo "this is $1+$2"
echo $#
} kevin_3() {
echo "this is $1!!"
} kevin_1 安徽
kevin_2 上海 北京
kevin_3 /root/pass.list [root@ss-server ~]# sh test.sh
this is 安徽
this is 上海+北京
2
this is /root/pass.list!! 示例6:函数的参数
在一个Shell脚本当中:
函数外的参数,函数可以直接调用;
函数内的参数,只要运行过函数,外部也可以直接调用。
[root@ss-server ~]# cat test.sh
#!/bin/bash str="hello world"
function kevin(){
bo="${str} is very nice!!"
} kevin
echo "${bo}, 666~" [root@ss-server ~]# sh test.sh
hello world is very nice!!, 666~ 示例7:导入库文件
说白了,就是在一个shell脚本中导入另一个脚本,导入脚本中的变量在新脚本中同样有效可用!
[root@ss-server ~]# cat /root/haha.sh
#!/bin/bash USER=$1
ADDRESS=$2
AGE=$3 function PER(){
if [ ${AGE} -gt 30 ];then
echo "来自${ADDRESS}的${USER}是一个大叔!"
fi
} [root@ss-server ~]# cat test.sh
#!/bin/bash #可以使用soirce或.导入库文件
#source /root/haha.sh
. /root/haha.sh function TES {
YOU=`PER`
echo "告诉你!${YOU}"
} TES [root@ss-server ~]# sh test.sh 李楠 霍城 38
告诉你!来自霍城的李楠是一个大叔! 示例8:在"~/.bashrc"文件中定义Shell函数
[root@ss-server ~]# cat ~/.bashrc
........
#定义PER函数
USER=$1
ADDRESS=$2
AGE=$3
function PER(){
if [ ${AGE} -gt 30 ];then
echo "来自${ADDRESS}的${USER}是一个大叔!"
fi
} [root@ss-server ~]# cat test.sh
#!/bin/bash source ~/.bashrc function TES {
YOU=`PER`
echo "告诉你!${YOU}"
} TES [root@ss-server ~]# sh test.sh 李楠 霍城 38
告诉你!来自霍城的李楠是一个大叔! --------------------------------
或者:
[root@ss-server ~]# cat ~/.bashrc
......
source /root/haha.sh [root@ss-server ~]# cat /root/haha.sh
#!/bin/bash USER=$1
ADDRESS=$2
AGE=$3 function PER(){
if [ ${AGE} -gt 30 ];then
echo "来自${ADDRESS}的${USER}是一个大叔!"
fi
} [root@ss-server ~]# cat test.sh
#!/bin/bash source ~/.bashrc function TES {
YOU=`PER`
echo "告诉你!${YOU}"
} TES [root@ss-server ~]# sh test.sh 李楠 霍城 38
告诉你!来自霍城的李楠是一个大叔!
14)Shell获取随机数 的 random 用法
1)使用$RANDOM
需要系统支持,通过echo来检测, 打印出一个随机数字,证明当前环境支持$RANDOM,反之为空不支持:
[root@bz3aomsmsap1002 ~]# echo $RANDOM
1525
[root@bz3aomsmsap1002 ~]# echo $RANDOM
16218 2)使用/dev/urandom + tr
[root@bz3aomsmsap1002 ~]# tr -cd 0-9 </dev/urandom | head -c 8 #取8位随机种子
67128612
[root@bz3aomsmsap1002 ~]# tr -cd 0-9 </dev/urandom | head -c 16 #取12位随机种子
8398375834495017 随机生成密码(如下两种方式都可以,生成16位长度的随机密码)
[root@bz3aomsmsap1002 ~]# head /dev/urandom | tr -dc A-Za-z0-9 | head -c 16
gXeLJ5XLAaV26tKJ
[root@bz3aomsmsap1002 ~]# tr -dc A-Za-z0-9 </dev/urandom | head -c 16
0PUw4BHWQw8oQ3ai
15)快速去除文件或字符串中的空格(使用sed或tr)
1. 删除字符串中的空格(使用sed或tr)
[root@ss-server ~]# echo "aa dd"|sed 's/ //g'
aadd
[root@ss-server ~]# echo "aa dd"|tr -d " "
aadd
[root@ss-server ~]# echo " aa b t "|tr -d " "
aabt
[root@ss-server ~]# echo " root, bin, hook"|tr -d " "
root,bin,hook 2. 删除文件中行首空格的命令
# sed 's/^[ \t]*//g' filename #不加-i参数,表示仅仅在当前终端显示命令执行效果。
# sed -i 's/^[ \t]*//g' filename #加-i参数,表示命令执行效果直接为文件生效,即直接在文件中删除行首空格。 命令解释:
第一个/的左边是s表示替换,即将空格替换为空。
第一个/的右边是中括号表示"或",空格或tab中的任意一种。这是正则表达式的规范。
中括号右边是*,表示一个或多个。
第二个和第三个\中间没有东西,表示空
g表示替换原来buffer(缓冲区)中的,sed在处理字符串的时候并不对源文件进行直接处理,先创建一个buffer,但是加g表示对原buffer进行替换
整体的意思是:用空字符去替换一个或多个用空格或tab开头的本体字符串 示例:
[root@ss-server ~]# cat test
aa
bb
123 aa
sadf
12313 yy
45
[root@ss-server ~]# cat test|sed 's/^[ \t]*//g' test
aa
bb
123 aa
sadf
12313 yy
45
[root@ss-server ~]# cat test|sed -i 's/^[ \t]*//g' test
[root@ss-server ~]# cat test
aa
bb
123 aa
sadf
12313 yy
45 3. 删除文件中行尾空格的命令
# sed 's/[ \t]*$//g' filename #仅仅在当前终端显示执行效果。
# sed -i 's/[ \t]*$//g' filename #直接删除文件中行尾空格。 命令解释:
和上面稍微有些不同是前面删除了^符,在后面加上了美元符。表示删除行尾空格。 4. 删除文件中所有的空格的命令
# sed s/[[:space:]]//g filename
# sed 's/[[:space:]]//g' haha
# sed -i 's/[[:space:]]//g' haha
# cat filename|tr -d " " #使用tr删除所有空格,只是在终端显示里生效,文件里默认并不会生效 示例:
[root@ss-server ~]# cat haha
12 3 4
ads ss
12 3123 asdf
ok jk 1
[root@ss-server ~]# sed 's/[[:space:]]//g' haha
1234
adsss
123123asdf
okjk1
[root@ss-server ~]# cat haha
12 3 4
ads ss
12 3123 asdf
ok jk 1
[root@ss-server ~]# sed -i 's/[[:space:]]//g' haha
[root@ss-server ~]# cat haha
1234
adsss
123123asdf
okjk1 [root@ss-server ~]# cat haha
12 3 4
ads ss
12 3123 asdf
ok jk 1
[root@ss-server ~]# cat haha|tr -d " "
1234
adsss
123123asdf
okjk1
[root@ss-server ~]# cat haha
12 3 4
ads ss
12 3123 asdf
ok jk 1
[root@ss-server ~]# cat haha|tr -d " " > haha.txt && \cp -f haha.txt haha && rm -f haha.txt
[root@ss-server ~]# cat haha
1234
adsss
123123asdf
okjk1
16)如何根据截取某个字段多少位进行去重?以及连续重复字符去重
一、tr命令加-s参数,表示把连续重复的字符以单独一个字符表示。即压缩字符,但是必须是连续重复的单个字符!注意是连续出现的"单个"字符!!
[root@ss-server ~]# echo "111222342133"|tr -s "1"
1222342133
[root@ss-server ~]# echo "111222342133"|tr -s "12"
12342133
[root@ss-server ~]# echo "111222342133"|tr -s "123"
1234213
[root@ss-server ~]# echo "aa966ha34jj9"|tr -s "a"
a966ha34jj9
[root@ss-server ~]# echo "aa966ha34jj9"|tr -s "a96"
a96ha34jj9 还可以使用正则
[root@ss-server ~]# echo "aaAAF7889HHjkk09"|tr -s "a-zA-Z0-9"
aAF789Hjk09 二、根据下面test文件的第一个字段、第二个字段截取前8位进行排序去重
[root@ss-server ~]# cat /root/test
25ds51dd225d86af,20180725115911,22570,20443,120.17138,30.119047
002a51dd225d86af,20180725120017,22570,184680195,120.176506,30.11527
002a51dd225d86af,20180725120058,22290,80489347,120.1810786,30.10003
002a51dd225d86af,20180725120149,22290,80489345,120.1810786,30.10003
002a51dd225d86af,20180725120209,22290,189880577,120.18859,30.093405
102a51dd225d86af,20180725120239,22290,155606668,120.1990471,30.0961
002a51dd225d86af,20180725120303,22290,155606666,120.1990468,30.0961
002a51dd225d86af,20180725120434,22290,193501442,120.220661,30.09723
002a79ded185cb04,20180725125428,22570,185263107,120.1576002,30.1293
002a79ded185cb04,20180726125649,22290,80489347,120.1810786,30.10003 运用的技巧:
echo ${var:0:8} 表示从${var}变量的第1个字符(左边的下标从0开始)开始截取,截取的总个数为8!
xargs -n2 表示将前面命令的结果按照每行2列显示(从第一行开始算,往下每行2列,直至分配完为止,不够的就是一列)
sort|uniq 表示去重,仅仅去掉连续出现的相同记录 1)脚本1:打印test文件的第一个和第二个字段以及自个截取的前面八位字符。
[root@ss-server ~]# cat test_0.sh
#!/bin/bash file=$(cat /root/test)
while read line
do
#输出每一行
echo line=${line} #截取一行的第一列
column1=`echo ${line}| cut -d "," -f1`
echo ${column1}
#输出前8个字符
echo ${column1:0:8} #截取一行的第二列
column2=`echo ${line}| cut -d "," -f2`
echo ${column2}
#输出前8个字符
echo ${column2:0:8}
done <<EOF
${file}
EOF [root@ss-server ~]# sh test_0.sh
line=25ds51dd225d86af,20180725115911,22570,20443,120.17138,30.119047
25ds51dd225d86af
25ds51dd
20180725115911
20180725
line=002a51dd225d86af,20180725120017,22570,184680195,120.176506,30.11527
002a51dd225d86af
002a51dd
20180725120017
20180725
line=002a51dd225d86af,20180725120058,22290,80489347,120.1810786,30.10003
002a51dd225d86af
002a51dd
20180725120058
20180725
line=002a51dd225d86af,20180725120149,22290,80489345,120.1810786,30.10003
002a51dd225d86af
002a51dd
20180725120149
20180725
line=002a51dd225d86af,20180725120209,22290,189880577,120.18859,30.093405
002a51dd225d86af
002a51dd
20180725120209
20180725
line=102a51dd225d86af,20180725120239,22290,155606668,120.1990471,30.0961
102a51dd225d86af
102a51dd
20180725120239
20180725
line=002a51dd225d86af,20180725120303,22290,155606666,120.1990468,30.0961
002a51dd225d86af
002a51dd
20180725120303
20180725
line=002a51dd225d86af,20180725120434,22290,193501442,120.220661,30.09723
002a51dd225d86af
002a51dd
20180725120434
20180725
line=002a79ded185cb04,20180725125428,22570,185263107,120.1576002,30.1293
002a79ded185cb04
002a79de
20180725125428
20180725
line=002a79ded185cb04,20180726125649,22290,80489347,120.1810786,30.10003
002a79ded185cb04
002a79de
20180726125649
20180726 2)脚本2: 改进下,仅仅获取第一个和第二个字段的前面8位字符
[root@ss-server ~]# cat test_1.sh
#!/bin/bash file=$(cat /root/test)
while read line
do
#输出每一行
#echo line=${line} #截取一行的第一列
column1=`echo ${line}| cut -d "," -f1`
#echo ${column1}
#输出前8个字符
echo ${column1:0:8} #截取一行的第二列
column2=`echo ${line}| cut -d "," -f2`
#echo ${column2}
#输出前8个字符
echo ${column2:0:8}
done <<EOF
${file}
EOF [root@ss-server ~]# sh test_1.sh
25ds51dd
20180725
002a51dd
20180725
002a51dd
20180725
002a51dd
20180725
002a51dd
20180725
102a51dd
20180725
002a51dd
20180725
002a51dd
20180725
002a79de
20180725
002a79de
20180726 3)接着继续改进,获取第一个和第二个字段的前面8位字符,并排序去重
[root@ss-server ~]# sh test_1.sh |xargs -n2
25ds51dd 20180725
002a51dd 20180725
002a51dd 20180725
002a51dd 20180725
002a51dd 20180725
102a51dd 20180725
002a51dd 20180725
002a51dd 20180725
002a79de 20180725
002a79de 20180726
[root@ss-server ~]# sh test_1.sh |xargs -n2|sort|uniq
002a51dd 20180725
002a79de 20180725
002a79de 20180726
102a51dd 20180725
25ds51dd 20180725
[root@ss-server ~]# sh test_1.sh |xargs -n2|sort|uniq -u|sed 's/ /,/g'
002a51dd,20180725
002a79de,20180725
002a79de,20180726
102a51dd,20180725
25ds51dd,20180725
17)shell特殊符号:sort排序,wc统计,uniq去重,tee,split
1)shell特殊符号
* 任意个任意字符。可以是单个字符,也可以是多个字符。
? 任意一个字符。只能是单个字符
# 注释字符
\ 脱义字符,转义符号 $ 变量的前缀
$ 正则里面表示行尾
^ 正则里面表示行首
; 多条命令写到一行,用;分割
~ 用户的家目录。正则表达式里表示匹配符
& 把命令放到后台
> 正确重定向
>> 正确追加重定向
2> 错误重定向
2>> 错误追加重定向
&> 正确错误重定向。 通过在一条命令后面加上">/dev/null 2>&1"表示这条命令执行后不打印任何信息,执行正确或错误信息都不打印!
&& 当前面的命令执行成功时,才执行后面的命令
|| 用在shell中表示或者的意思,如果第一条命令执行成功,则不执行第二条命令。如果第一条命令不成功,则执行第二条命令 [root@ss-server ~]# xx=aa
[root@ss-server ~]# yy=bb
[root@ss-server ~]# echo ${xx}${yy}
aabb
[root@ss-server ~]# echo ${xx}\${yy}
aa${yy}
[root@ss-server ~]# echo \${xx}\${yy}
${xx}${yy} 2)管道符和cut
cut 截取
-d 指定分隔符
-f 指定截取那一段 # cat filename|cut -d":" -f2 打印filename文件中以:分割的第2列
# cat filename|cut -d ":" -f 1-3 打印filename文件中以:分割的第1到3列,但是会保留分隔符!!!!! [root@ss-server ~]# cat test|cut -d"/" -f2
b
2
[root@ss-server ~]# cat test|cut -d"/" -f1-3
a/b/c
1/2/3 [root@ss-server ~]# cat test|awk -F"/" '{print $2}'
b
2
[root@ss-server ~]# cat test|awk -F"/" '{print $1$2$3}'
abc
123
[root@ss-server ~]# cat test|awk -F"/" '{print $1"/"$2"/"$3}'
a/b/c
1/2/3 3)sort、uniq、wc、split、tee命令
===========================================
sort 排序命令
uniq 去重命令 sort -n 默认以数字去排序(默认字母和特殊符号为0,所以会排在最前面)
sort -r 反序排序,即升序。默认是降序排序
sort -kn 以第n列排序(默认降序)
sort -kn -r 以第n列降序排序 sort|uniq 排序去重
sort|uniq -c 排序去重,并打印每个出现的次数。即重复次数
sort|uniq -d 打印出交集部分,即打印出那些重复、相同的字符
sort|uniq -u 打印出除了交集之外的部分。即打印出那些去掉重复字符之后的字符 sort|uniq|sort -k3 #排序去重,并按第3列排序(降序)
sort|uniq|sort -k3 -rn #排序去重,并按第3列排序(降序)
sort|uniq|sort -k3 -r #排序去重,并按第3列排序(升序) [root@ss-server ~]# cat test
11
ad
0
34
3
21
4
[root@ss-server ~]# cat test|sort -n
0
ad
3
4
11
21
34
[root@ss-server ~]# cat test|sort -rn
34
21
11
4
3
ad
0 [root@ss-server ~]# cat haha
aa 11 hj
2b 7 ok
23 100 jo
op 32 fg
[root@ss-server ~]# cat haha|sort -k2
23 100 jo
aa 11 hj
op 32 fg
2b 7 ok
[root@ss-server ~]# cat haha|sort -k2 -r
2b 7 ok
op 32 fg
aa 11 hj
23 100 jo
[root@ss-server ~]# cat haha|sort -k2 -rn
23 100 jo
op 32 fg
aa 11 hj
2b 7 ok [root@ss-server ~]# cat test
wang bo
wang bo
kevin ai
han hu
han hu
wang bo
xiao ru
han hu
[root@ss-server ~]# cat test|sort|uniq
han hu
kevin ai
wang bo
xiao ru
[root@ss-server ~]# cat test|sort|uniq -d
han hu
wang bo
[root@ss-server ~]# cat test|sort|uniq -u
kevin ai
xiao ru ----------------------------------
uniq与sort -u 两种"去重"的区别???? uniq 针对的重复是连续出现的相同记录!
sort -u 针对的所有出现的相同记录,包括连续出现和非连续出现的相同记录! sort -u 相当于 sour|uniq [root@ss-server ~]# cat hehe
wang
wang
wang
bobo
wang
[root@ss-server ~]# cat hehe|uniq
wang
bobo
wang
[root@ss-server ~]# uniq hehe
wang
bobo
wang
[root@ss-server ~]# cat hehe|sort -u
bobo
wang
[root@ss-server ~]# sort -u hehe
bobo
wang
[root@ss-server ~]# cat hehe|sort|uniq
bobo
wang ===========================================
wc 统计
wc file 默认统计file文件的行数、单词数,以及该文件的字节数。即默认加了-l、-w、-c -l 统计行数
-c 统计字节数
-w 统计字符串,即统计单词数 (默认以空白格或,为分隔符)
-m 统计字符数 (隐藏的换行符也算,用cat -A 查看隐藏符号)
-L 显示最长行的长度 [root@ss-server ~]# cat test
wang bo
zhang heng yuan
xiao ru
zhu ge shen hou
[root@ss-server ~]# wc test
4 11 49 test
[root@ss-server ~]# cat test|wc -l -w -c
4 11 49 [root@ss-server ~]# cat test|wc -l
4
[root@ss-server ~]# cat test|wc -w
11
[root@ss-server ~]# cat test|wc -c
49
[root@ss-server ~]# cat test|wc -m
49 [root@ss-server ~]# cat test|wc -L
16 [root@ss-server ~]# cat -A test
wang bo$
zhang heng yuan $
xiao ru$
zhu ge shen hou$ [root@ss-server ~]# cat test.sh
#!/bin/bash file=$(cat /root/test)
while read line
do
echo "${line} 这一行的字节数为: $(echo ${line}|wc -c)"
done <<EOF
${file}
EOF
[root@ss-server ~]# sh test.sh
wang bo 这一行的字节数为: 8
zhang heng yuan 这一行的字节数为: 16
xiao ru 这一行的字节数为: 8
zhu ge shen hou 这一行的字节数为: 16 ===========================================
tee 和输出重定>向有点像,但是把重定向的内容打印到屏幕上, 即打印到终端屏幕上
-a 追加,和>>相似 [root@ss-server ~]# cat /etc/passwd|head -2
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@ss-server ~]# cat /etc/passwd|head -2|tee
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@ss-server ~]# cat /etc/passwd|head -2|tee > aa.txt
[root@ss-server ~]# cat aa.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@ss-server ~]# cat /etc/passwd|head -2|tee >> aa.txt
[root@ss-server ~]# cat aa.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin ===========================================
split 用于将一个文件分割成数个。该指令将大文件分割成较小的文件,在默认情况下将按照每1000行切割成一个小文件。 split -b 100M filename 以文件大小切割 (可以指定文件前缀,默认是x开头)
split -l 1000 filename 以行数切割,相当于"split -1000" filename [root@ss-server ~]# du -sh aa
710M aa
[root@ss-server ~]# split -b 100M aa #指定按照每个小文件100M的大小来分割aa文件
[root@ss-server ~]# du -sh *
710M aa
100M xaa
100M xab
100M xac
100M xad
100M xae
100M xaf
100M xag
9.7M xah [root@ss-server mnt]# cat bb
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt [root@ss-server mnt]# cat bb|wc -l
8
[root@ss-server mnt]# split -2 bb #相当于"split -l 2 bb" 表示指定按照每个小文件2行来分割bb文件
[root@ss-server mnt]# ls
bb xaa xab xac xad
[root@ss-server mnt]# cat xaa
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@ss-server mnt]# cat xab
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
[root@ss-server mnt]# cat xac
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
[root@ss-server mnt]# cat xad
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt [root@ss-server mnt]# rm -rf x*
[root@ss-server mnt]# ls
bb
[root@ss-server mnt]# du -sh -b bb #查看bb文件的字节数
293 bb
[root@ss-server mnt]# split -b 100 bb #按照每个小文件100个字节来分割bb文件
[root@ss-server mnt]# ls
bb xaa xab xac
[root@ss-server mnt]# du -sh -b xaa
100 xaa
[root@ss-server mnt]# du -sh -b xab
100 xab
[root@ss-server mnt]# du -sh -b xac
93 xac [root@ss-server mnt]# du -sh bb
32K bb
[root@ss-server mnt]# split -b 8K bb
[root@ss-server mnt]# ls
bb xaa xab xac xad
[root@ss-server mnt]# du -sh xaa
8.0K xaa
[root@ss-server mnt]# du -sh xab
8.0K xab
[root@ss-server mnt]# du -sh xac
8.0K xac
[root@ss-server mnt]# du -sh xad
8.0K xad 小结:
spilt -n 相当于 split -l n 表示按照多少行数来分割成小文件
split -b 按照大小分割成小文件,默认是K,至少是4.0K(即新建文件默认大小) split -b 10K 按照每10K一个文件分割成小文件
split -b 10M 按照每10M一个文件分割成小文件
split -b 10G 按照每10G一个文件分割成小文件
split -b 100 按照每100 byte字节一个文件分割成小文件
18)按照文件中的单词及字母去重排序
使用shell脚本实现单词及字母去重排序 需求
1. 按单词出现频率降序排序!
2. 按字母出现频率降序排序! [root@ss-server ~]# cat test
wang shi hu shi kui shi juan wang fang fang anhui of huoqiu liuan the squid project provides a number of.
resources to assist users Newsgd.com is the premier New online source of Guangdong news and information,
fully displaying shi Guangdong through is channels including Guangdong New [root@ss-server ~]# cat test.sh
#!/bin/bash file=$(cat /root/test) echo "按单词出现频率降序排序!"
for i in ${file}
do
echo ${i}
done|\
sort |uniq -c|sort -nk1 -r
echo "按字母出现频率降序排序!"
echo ${file} |grep -o "[a-z]" |sort|uniq -c |sort -nk1 -r [root@ss-server ~]# sh test.sh
按单词出现频率降序排序!
4 shi
3 Guangdong
2 wang
2 the
2 of
2 New
2 is
2 fang
1 users
1 to
1 through
1 squid
1 source
1 resources
1 provides
1 project
1 premier
1 online
1 of.
1 number
1 Newsgd.com
1 news
1 liuan
1 kui
1 juan
1 information,
1 including
1 huoqiu
1 hu
1 fully
1 displaying
1 channels
1 assist
1 anhui
1 and
1 a
按字母出现频率降序排序!
25 n
21 i
20 s
18 u
17 o
17 e
16 a
14 g
12 h
11 r
9 d
7 t
7 l
7 f
6 w
6 c
4 p
4 m
2 y
2 q
2 j
1 v
1 k
1 b 如果在命令行直接操作,如下:
[root@ss-server ~]# echo "按单词出现频率降序排序!" && for i in $(cat /root/test);do echo ${i};done|sort |uniq -c|sort -nk1 -r
按单词出现频率降序排序!
4 shi
3 Guangdong
2 wang
2 the
2 of
2 New
2 is
2 fang
1 users
1 to
1 through
1 squid
1 source
1 resources
1 provides
1 project
1 premier
1 online
1 of.
1 number
1 Newsgd.com
1 news
1 liuan
1 kui
1 juan
1 information,
1 including
1 huoqiu
1 hu
1 fully
1 displaying
1 channels
1 assist
1 anhui
1 and
1 a [root@ss-server ~]# echo "按字母出现频率降序排序!" && echo $(cat /root/test) |grep -o "[a-z]" |sort|uniq -c |sort -nk1 -r
按字母出现频率降序排序!
25 n
21 i
20 s
18 u
17 o
17 e
16 a
14 g
12 h
11 r
9 d
7 t
7 l
7 f
6 w
6 c
4 p
4 m
2 y
2 q
2 j
1 v
1 k
1 b grep -o 代表的是只输出匹配的选项
19)join 命令用法
join命令用于将两个文件中,指定栏位内容相同的行连接起来。
注意:仅仅只能连接两个文件!!超过两个文件就无效! 语法格式:
join [-i][-a<1或2>][-e<字符串>][-o<格式>] [-t<字符>][-v<1或2>][-1<栏位>][-2<栏位>][--help] [--version][文件1][文件2] 补充说明:找出两个文件中,指定栏位内容相同的行,并加以合并,再输出到标准输出设备。 参数:
-a<1或2> 除了显示原来的输出内容之外,还显示指令文件中没有相同栏位的行。
-e<字符串> 若[文件1]与[文件2]中找不到指定的栏位,则在输出中填入选项中的字符串。
-i 比较栏位内容时,忽略大小写的差异。
-o<格式> 按照指定的格式来显示结果。
-t<字符> 使用栏位的分隔字符。
-v<1或2> 跟-a相同,但是只显示文件中没有相同栏位的行。
-1<栏位> 连接[文件1]指定的栏位。
-2<栏位> 连接[文件2]指定的栏位。 示例:
1)内连接(忽略不匹配的行)
=============================================================================
不指定任何参数的情况下使用join命令,就相当于数据库中的内连接,关键字不匹配的行不会输出。
不指定参数,即通过两个文件中相同元素进行连接,如下两个文件相同的就是第一列的1,2,3,4,5,6,其他多余的都删除
[root@ss-server ~]# cat test1
1 wang
2 han
3 niu
4 xiao
5 ping
6 hang
[root@ss-server ~]# cat test2
1 张三
2 徐思
3 刘磊
4 杨洋
5 李玉
6 王一
7 张麻
8 赫赫
[root@ss-server ~]# join test1 test2
1 wang 张三
2 han 徐思
3 niu 刘磊
4 xiao 杨洋
5 ping 李玉
6 hang 王一 [root@ss-server ~]# cat test3
1 w2
3 r4
4 y7
5 ij
[root@ss-server ~]# join test3 test2
1 w2 张三
3 r4 刘磊
4 y7 杨洋
5 ij 李玉 2)左连接(又称左外连接,显示左边所有记录)。 也就是以左边件为主!!!
=============================================================================
显示左边文件中的所有记录,右边文件中没有匹配的显示空白。
[root@ss-server ~]# join -a1 test1 test2
1 wang 张三
2 han 徐思
3 niu 刘磊
4 xiao 杨洋
5 ping 李玉
6 hang 王一
[root@ss-server ~]# join -a1 test3 test2
1 w2 张三
3 r4 刘磊
4 y7 杨洋
5 ij 李玉 3)右连接(又称右外连接,显示右边所有记录)。也就是以右边文件为主!!!
=============================================================================
显示右边文件中的所有记录,左边文件中没有匹配的显示空白。
[root@ss-server ~]# join -a2 test1 test2
1 wang 张三
2 han 徐思
3 niu 刘磊
4 xiao 杨洋
5 ping 李玉
6 hang 王一
7 张麻
8 赫赫
[root@ss-server ~]# join -a2 test3 test2
1 w2 张三
2 徐思
3 r4 刘磊
4 y7 杨洋
5 ij 李玉
6 王一
7 张麻
8 赫赫 4)全连接(又称全外连接,显示左边和右边所有记录)
=============================================================================
[root@ss-server ~]# join -a1 -a2 test1 test2
1 wang 张三
2 han 徐思
3 niu 刘磊
4 xiao 杨洋
5 ping 李玉
6 hang 王一
7 张麻
8 赫赫
[root@ss-server ~]# join -a1 -a2 test3 test2
1 w2 张三
2 徐思
3 r4 刘磊
4 y7 杨洋
5 ij 李玉
6 王一
7 张麻
8 赫赫 5)指定输出字段
=============================================================================
比如参数 -o 1.1 表示只输出第一个文件的第一个字段。
[root@ss-server ~]# join -o 1.1 test1 test2
1
2
3
4
5
6
[root@ss-server ~]# join -o 1.1 test3 test2
1
3
4
5 -o 1.2 只输出第一个文件的第二个字段
[root@ss-server ~]# join -o 1.2 test1 test2
wang
han
niu
xiao
ping
hang
[root@ss-server ~]# join -o 1.2 test3 test2
w2
r4
y7
ij [root@ss-server ~]# join -o 1.2 2.2 test1 test2
wang 张三
han 徐思
niu 刘磊
xiao 杨洋
ping 李玉
hang 王一 [root@ss-server ~]# join -o 2.2 1.2 test1 test2
张三 wang
徐思 han
刘磊 niu
杨洋 xiao
李玉 ping
王一 hang [root@ss-server ~]# join -o 1.1 2.2 test1 test2
1 张三
2 徐思
3 刘磊
4 杨洋
5 李玉
6 王一 6)指定分隔符
=============================================================================
join -t "分隔符" 注意:这个分隔符必须是两个文件中都存在的!!
[root@ss-server ~]# join -t ':' test1 test2
[root@ss-server ~]# join -t ' ' test1 test2
1 wang 张三
2 han 徐思
3 niu 刘磊
4 xiao 杨洋
5 ping 李玉
6 hang 王一 [root@ss-server ~]# cat haha1
a:11:aa:111:aaa
b:22:aff:5t
c:33:hji:o0p:p8u
[root@ss-server ~]# cat haha2
a:nj:5:c
b:ok:90
c:yh8
d:p:0:9
[root@ss-server ~]# join -t ":" haha1 haha2
a:11:aa:111:aaa:nj:5:c
b:22:aff:5t:ok:90
c:33:hji:o0p:p8u:yh8
20)paste 命令用法
paste 命令用于合并文件的列,会把每个文件以列对列的方式,一列列地加以合并。
语法
paste [-s][-d <间隔字符>][--help][--version][文件...] 参数:
-d<间隔字符>或--delimiters=<间隔字符> : 用指定的间隔字符取代跳格字符。
-s或--serial: 串列进行而非平行处理。
--help: 在线帮助。
--version: 显示帮助信息。
[文件…]: 指定操作的文件路径 比如:
paste file testfile testfile1 #合并指定文件的内容
paste file testfile testfile1 -d ":" #合并指定文件的内容,并使用逗号隔开。-d后面的分隔符可以自行定义!
paste -s file1 file2 #将file1和file2文件的各自多行内容合并到各自的一行里面进行展示。使用-s参数可以将一个文件中的多行数据合并为一行进行显示。 注意:
paste 可以针对多个文件进行合并!!也可以针对一个文件进行处理!
join 只能针对两个文件进行连接!!! 示例如下:
[root@ss-server ~]# cat aa.txt
11
22
33
44
55
[root@ss-server ~]# cat bb.txt
aa
ab
ac
cc
cd 使用paste命令将文件进行合并
[root@ss-server ~]# paste aa.txt bb.txt
11 aa
22 ab
33 ac
44 cc
55 cd 合并后使用":"隔开
[root@ss-server ~]# paste -d":" aa.txt bb.txt
11:aa
22:ab
33:ac
44:cc
55:cd 合并后使用"-"隔开
[root@ss-server ~]# paste -d"-" aa.txt bb.txt
11-aa
22-ab
33-ac
44-cc
55-cd paste -s 可以将一个文件中的多行内容合并为一行。例如:
[root@ss-server ~]# cat file
111
222
333
444
555
[root@ss-server ~]# cat file |paste -s
111 222 333 444 555
[root@ss-server ~]# cat file |paste -s -d":"
111:222:333:444:555
[root@ss-server ~]# cat file |paste -s -d ":"
111:222:333:444:555
[root@ss-server ~]# cat file |paste -s -d "-"
111-222-333-444-555
[root@ss-server ~]# cat file |paste -s -d "---"
111-222-333-444-555
[root@ss-server ~]# cat file |paste -s -d ","
111,222,333,444,555 看下面一个小需求:
有一个log.txt文件,第二列是ip,现在需要将log.txt文件中的ip列取出来放在一行,并用逗号隔开。 第一种做法:awk + paste
[root@ss-server ~]# cat log.txt
17:05 172.16.60.34 sadfjsafjsdf
17:14 172.16.60.35 asdfasudfasjfasjfklsafsaf
17:45 172.16.60.38 dsafkjdsajflsajfadf [root@ss-server ~]# cat log.txt
17:05 172.16.60.34 sadfjsafjsdf
17:14 172.16.60.35 asdfasudfasjfasjfklsafsaf
17:45 172.16.60.38 dsafkjdsajflsajfadf [root@ss-server ~]# cat log.txt |awk '{print $2}'
172.16.60.34
172.16.60.35
172.16.60.38 [root@ss-server ~]# cat log.txt |awk '{print $2}'|paste -s
172.16.60.34 172.16.60.35 172.16.60.38 [root@ss-server ~]# cat log.txt |awk '{print $2}'|paste -s -d","
172.16.60.34,172.16.60.35,172.16.60.38 另一种做法是:awk + xargs + sed
[root@ss-server ~]# cat log.txt |awk '{print $2}'
172.16.60.34
172.16.60.35
172.16.60.38
[root@ss-server ~]# cat log.txt |awk '{print $2}'|xargs
172.16.60.34 172.16.60.35 172.16.60.38
[root@ss-server ~]# cat log.txt |awk '{print $2}'|xargs|sed 's/ /,/g'
172.16.60.34,172.16.60.35,172.16.60.38
21)su命令用法
su命令用于变更为其他使用者的身份,除 root 外,需要键入该使用者的密码。(即root用户使用su切换到其他用户不需要输入密码,其他用户之间使用su切换均需要输入密码)。 ===================================
1)su 和 su - 的区别
"su"命令仅仅是切换了用户身份,但用户的shell环境变量没有切换!即su切换用户身份后,环境变量还是切换前的用户的环境变量。
"su -"命令不仅切换了用户身份,用户的shell环境变量也一起切换!即su切换用户身份后,环境变量是切换后的用户的环境变量。 示例:
[root@ss-server ~]# su kevin
[kevin@ss-server root]$ whoami #用户身份切换了
kevin
[kevin@ss-server root]$ pwd #用户的环境变量没有切换
/root [root@ss-server ~]# su - kevin
Last login: Fri Dec 6 10:29:59 CST 2019 on pts/16
[kevin@ss-server ~]$ whoami #用户身份切换了
kevin
[kevin@ss-server ~]$ pwd #用户的环境变量也切换了
/home/kevin 2)-c 参数,表示切换到某用户后执行一些命令,注意,这个命令是在切换用户后的状态下执行的,并且执行命令后再变回原来的用户。
示例:
[root@ss-server ~]# su - kevin -c "pwd" #即是在切换到kevin用户状态下执行的"pwd"命令。这里使用"su -",即也切换了shell环境变量
/home/kevin
[root@ss-server ~]# su kevin -c "pwd" #即是在切换到kevin用户状态下执行的"pwd"命令。这里没有切换shell环境变量
/root su和sudo权限使用可参考:
https://www.cnblogs.com/kevingrace/p/5823003.html
https://www.cnblogs.com/kevingrace/p/6130008.html
22)test 命令用法
test 命令最短的定义可能是评估一个表达式;如果条件为真,则返回一个 0 值。如果表达式不为真,则返回一个大于 0 的值(一般为1),也可以将其称为假值。 需要注意:
1. 在shell中,test命令 和 [] 是同一个命令的不同名称。也就是说,test xxxx 等同于 [ xxxx ] 的形式!!,注意[]里面的内容两边要有空格!!
2. 检查最后所执行命令的状态的最简便方法是使用 $? 值。
3. test功能是检查文件和比较值。 test 和 [ ] 的语法如下:
test expression
[ expression ] 其中,expression为test命令构造的表达式。这里expression是test命令可以理解的任何有效表达式,该简化格式将是我们可能会踫见的最常用格式返回值:
test命令或者返回0(真) 或者返回1(假). 因为它们彼此互为别名,所以使用 test 或 [ ] 均需要一个表达式。表达式一般是文本、数字或文件和目录属性的比较,并且可以包含变量、常量和运算符。
运算符可以是字符串运算符、整数运算符、文件运算符或布尔运算符 — 我们将在以下各部分依次介绍每一种运算符。 test可理解的表达式类型分为四类:
1. 表达式判断
2. 字符串比较
3. 数字比较
4. 文件比较 1)判断表达式
--------------------------------------------------------
if test 表达式 #表达式为真
if test ! 表达式 #表达式为假
test 表达式1 –a 表达式 2 #两个表达式都为真
test 表达式1 –o 表达式2 #两个表达式有一个为真 2)判断字符串
--------------------------------------------------------
test –n 字符串 #字符串的长度非零。即非空字符串。
test –z 字符串 #字符串的长度为零。即空字符串。
test 字符串1=字符串 2 #字符串相等
test 字符串1 !=字符串2 #字符串不等 3)判断整数
--------------------------------------------------------
test 整数1 –eq 整数2 #整数相等
test 整数1 –ne 整数 2 #整数1不等于整数2
test 整数 1 –ge 整数2 #整数1大于等于整数2
test 整数1 –gt 整数 2 #整数1大于整数2
test 整数1 –le 整数 2 #整数1小于等于整数2
test 整数1 –lt 整数 2 #整数1小于整数2 4)判断文件
--------------------------------------------------------
test File1 –nt File2 #文件1比文件2新(new)
test File1 –ot File2 #文件1比文件2旧(old)
test File1 –ef File2 #判断两个文件是否与同一个设备相连,是否拥有相同的inode号
test –d File #文件存在并且是目录
test –e File #文件存在
test –f File #文件存在并且是正规文件
test –h File #文件存在并且是一个符号链接(同-L)。即存在且是软链接文件
test –L File #文件存在并且是一个符号链接(同-h)。即存在且是软链接文件
test –k File #文件存在并且设置了sticky位(即设置了t权限)
test –r File #文件存在并且可读
test –w File #文件存在并且可写
test –x File #文件存在并且可执行 示例如下:
1)判断表达式。下面hang.txt文件是不存在的。
[root@ss-server ~]# cat test.sh
#!/bin/bash
if test `cat /hang.txt`;then
echo "haha.txt is exist"
else
echo "haha.txt is not exist"
fi [root@ss-server ~]# sh test.sh
cat: /hang.txt: No such file or directory
haha.txt is not exist [root@ss-server ~]# cat test.sh
#!/bin/bash
if test !`cat /hang.txt >/dev/null 2>&1`;then
echo "haha.txt is exist"
else
echo "haha.txt is not exist"
fi
[root@ss-server ~]# sh test.sh
haha.txt is exist 使用[]的形式操作上面的脚本
[root@ss-server ~]# cat test.sh
#!/bin/bash
if [ `cat /hang.txt` ];then
echo "haha.txt is exist"
else
echo "haha.txt is not exist"
fi [root@ss-server ~]# sh test.sh
cat: /hang.txt: No such file or directory
haha.txt is not exist [root@ss-server ~]# cat test.sh
#!/bin/bash
if [ !`cat /hang.txt >/dev/null 2>&1` ];then
echo "haha.txt is exist"
else
echo "haha.txt is not exist"
fi [root@ss-server ~]# sh test.sh
haha.txt is exist 2)判断第一个参数是否为空字符串,不空则打印该字符串,为空则打印"空字符串"
[root@ss-server ~]# cat test.sh
#!/bin/bash
if test -n "$1";then
echo "$1"
else
echo "空字符串"
fi 执行结果:
[root@ss-server ~]# sh test.sh beijing
beijing
[root@ss-server ~]# sh test.sh
空字符串 由于test xxxx 等同于 [ xxxx ] 的形式,所以上面还可以改成:
[root@ss-server ~]# cat test.sh
#!/bin/bash
if [ -n "$1" ];then
echo "$1"
else
echo "空字符串"
fi 执行结果:
[root@ss-server ~]# sh test.sh shanghai
shanghai
[root@ss-server ~]# sh test.sh
空字符串 3)文件判断
[root@ss-server ~]# test -h heihei
[root@ss-server ~]# echo $?
0
[root@ss-server ~]# [ -h heihei ]
[root@ss-server ~]# echo $?
0 [root@ss-server ~]# test -x haha
[root@ss-server ~]# echo $?
1
[root@ss-server ~]# [ -x haha ]
[root@ss-server ~]# echo $?
1 [root@ss-server ~]# ll haha
-rw-r--r-- 1 root root 32 Dec 18 13:06 haha
[root@ss-server ~]# ll hehe
-rw-r--r-- 1 root root 0 Dec 19 17:19 hehe
[root@ss-server ~]# test haha -nt hehe
[root@ss-server ~]# echo $?
1
[root@ss-server ~]# [ haha -nt hehe ]
[root@ss-server ~]# echo $?
1 [root@ss-server ~]# test haha -ot hehe
[root@ss-server ~]# echo $?
0
[root@ss-server ~]# [ haha -ot hehe ]
[root@ss-server ~]# echo $?
0
23)printf 命令用法
关于printf的含义,需要注意下面四点:
1. printf 命令用于格式化输出,它是echo命令的增强版。它是C语言printf()库函数的一个有限的变形,并且在语法上有些不同。
2. printf 由 POSIX 标准所定义,因此使用 printf 的脚本比使用 echo 移植性好。
3. printf 使用引用文本或空格分隔的参数,外面可以在 printf 中使用格式化字符串,还可以制定字符串的宽度、左右对齐方式等。
4. 默认 printf 不会像 echo 自动添加换行符,但是可以手动添加 \n。 printf 命令的语法:
printf format-string [arguments...] 参数说明:
format-string: 为格式控制字符串
arguments: 为参数列表。 需要注意:
1. printf 不像 echo 那样会自动换行,必须显式添加换行符(\n)。
2. printf 命令不用加括号
3. format-string 可以没有引号,但最好加上,单引号双引号均可。
4. 参数多于格式控制符(%)时,format-string 可以重用,可以将所有参数都转换。
5. arguments 使用空格分隔,不用逗号。 示例如下:
echo默认自动换行。加上-n参数,则不换行
printf默认不会自动换行
[root@ss-server ~]# echo "Hello, Shell"
Hello, Shell
[root@ss-server ~]# echo -n "Hello, Shell"
Hello, Shell[root@ss-server ~]# [root@ss-server ~]# printf "Hello, Shell"
Hello, Shell[root@ss-server ~]# [root@ss-server ~]# printf "Hello, Shell\n"
Hello, Shell
[root@ss-server ~]# [root@ss-server ~]# printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
姓名 性别 体重kg
[root@ss-server ~]# printf "%-10s %-8s %-4.2f\n" 小明 男 65.1234
小明 男 65.12
[root@ss-server ~]# printf "%-10s %-8s %-4.2f\n" 小洋 男 72.6589
小洋 男 72.66
[root@ss-server ~]# printf "%-10s %-8s %-4.2f\n" 小梅 女 48.7167
小梅 女 48.72 需要注意:
%d指的是针对数字的格式化
%s指的是字符串的格式化
%-10s 指一个宽度为10个字符(-表示左对齐,没有则表示右对齐),任何字符都会被显示在10个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
%-4.2f 指格式化为小数,其中.2指保留2位小数。 示例如下:
format-string为双引号(换行)
[root@ss-server ~]# printf "%d %s\n" 1 "abc"
1 abc 单引号与双引号效果一样(换行)
[root@ss-server ~]# printf '%d %s\n' 1 "abc"
1 abc 没有引号也可以输出(不换行)
[root@ss-server ~]# printf %s abcdef
abcdef[root@ss-server ~]# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用
[root@ss-server ~]# printf %s abc def
abcdef[root@ss-server ~]# [root@ss-server ~]# printf "%s\n" abc def
abc
def [root@ss-server ~]# printf "%s %s %s\n" a b c d e f g h i j
a b c
d e f
g h i
j 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替
[root@ss-server ~]# printf "%s and %d \n"
and 0 如果以 %d 的格式来显示字符串,那么会有警告,提示无效的数字,此时默认置为 0
[root@ss-server ~]# printf "The first program always prints'%s,%d\n'" Hello Shell
-bash: printf: Shell: invalid number
The first program always prints'Hello,0 printf的转义序列
=================================================================================
\a 警告字符,通常为ASCII的BEL字符
\b 后退
\c 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略
\f 换页(formfeed)
\n 换行
\r 回车(Carriage return)
\t 水平制表符
\v 垂直制表符
\\ 一个字面上的反斜杠字符
\ddd 表示1到3位数八进制值的字符。仅在格式字符串中有效
\0ddd 表示1到3位的八进制值字符 示例如下:
[root@ss-server ~]# printf "welcome, 哈哈,北京:<%s>\n" "A\nB"
welcome, 哈哈,北京:<A\nB> [root@ss-server ~]# printf "welcome, 哈哈,北京::<%b>\n" "A\nB"
welcome, 哈哈,北京::<A
B> [root@ss-server ~]# printf "www.kevin.com \a"
www.kevin.com [root@ss-server ~]#
24)zcat 和 zgrep命令用法
服务器端常有很多压缩过的日志文件,当需要查找日志中某些特定信息的时候,为了避免解压文件,可以使用zgrep,zcat等命令查找、查看压缩文件中的信息。
1)gzip打包压缩文件
[root@localhost ~]# cat test
name:wangbo
age:29
address:beijing
school:lanzhoucaida [root@localhost ~]# gzip test
[root@localhost ~]# ls test.gz
test.gz ------------------------------------------------------------------
注意:
gzip filename # 将filename文件打包压缩成filename.gz
gzip -d filename.gz # 解压filename.gz文件
gzip -r dirname # 将dirname目录下的文件打包压缩为.gz格式的文件 gzip打包压缩一个文件,打包后,原文件就变成压缩文件,原文件不存在了!
----------------------------------------------------------------- 现在想在不解压的情况下查看或者搜索test.tar.gz文件中的数据 使用zcat命令
[root@localhost ~]# zcat test.gz |grep "age"
age:29 使用gzip命令
[root@localhost ~]# zgrep "age" test.gz
age:29
[root@localhost ~]# zgrep "age" test.gz |more
age:29 2)zip打包压缩文件
以上针对的是gzip压缩的gz格式的压缩文件,如果换成zip格式的话,效果如何?继续看下面:
[root@localhost ~]# gzip -d test.gz
[root@localhost ~]# zip test.zip test
adding: test (stored 0%)
[root@localhost ~]# ls test*
test test.zip
[root@localhost ~]# zcat test.zip
name:wangbo
age:29
address:beijing
school:lanzhoucaida
[root@localhost ~]# zgrep "address" test.zip
address:beijing
[root@localhost ~]# zgrep "address" test.zip |more
address:beijing ------------------------------------------------------------------
注意:
zip filename.zip filename #将filename文件打包压缩成filename.zip
unzip filename.zip #解压filename.zip文件
unzip -r xxx.zip ./* #当前目录的内容打包压缩为为xxx.zip文件
unzip -r dirname.zip dirname #当dirname目录打包压缩为dirname.zip文件 zip打包压缩后,原文件还存在,原文件和打包文件同时存在
------------------------------------------------------------------ 3)tar打包压缩文件
如果换成tar打包压缩文件,又该如何?继续往下看
[root@localhost ~]# ls test*
test test.zip
[root@localhost ~]# rm -f test.zip
[root@localhost ~]# tar -zvcf test.tar.gz test
test
[root@localhost ~]# ls test*
test test.tar.gz [root@localhost ~]# zgrep "age" test.tar.gz
Binary file (standard input) matches 上面报错是因为grep认为test.tar.gz是个二进制文件,无法grep查找。
解决办法:加上-a参数即可
[root@localhost ~]# zgrep -a "age" test.tar.gz
age:29
[root@localhost ~]# zgrep -a "age" test.tar.gz |more
age:29 [root@localhost ~]# zcat test.tar.gz
test0000644000000000000000000000006713576332517010475 0ustar rootrootname:wangbo
age:29
address:beijing
school:lanzhoucaida [root@localhost ~]# zgrep -a "name" test.tar.gz |more
test 可以看出,对于tar格式的压缩文件,zcat或zgrep查看或搜索,会在第一行多处一个字符串,
这个字符串是tar打包压缩后出现的,并把文件正文中的第一行内容和这个字符串放在一行!
这样当zgrep搜索内容的字段在原文第一行,则就搜索不出来了! ------------------------------------------------------------------
如果一个目录被打成tar包了,怎么查看这个tar包里有哪些文件?
如下,使用"tar -tvf"查看即可
[root@localhost ~]# tar -tvf test1.tar.gz
drwxr-xr-x root/root 0 2020-01-13 12:59 test1/
-rw-r--r-- root/root 7 2020-01-13 12:59 test1/b.txt
-rw-r--r-- root/root 7 2020-01-13 12:59 test1/a.txt
drwxr-xr-x root/root 0 2020-01-13 13:00 test1/haha/
-rw-r--r-- root/root 9 2020-01-13 13:00 test1/haha/test.txt
25); || && 区别
三种符号均用于多用命令之间的衔接。区别如下:
1); 符号,表示不论前面的命令执行结果是true还是false,后面的命令照样执行。
2)|| 符号,表示只有前面的命令执行结果为false时,后面的命令才会继续执行;如果前面命令执行结果为true,则后面的命令就不会继续执行了。
3)&& 符号,表示只有前面的命令执行结果为true时,后面的命令才会继续执行;如果前面命令执行结果为false,则后面的命令就不会继续执行了。 示例如下:
[root@kevin_test ~]# cat haha.txt
cat: haha.txt: No such file or directory
[root@kevin_test ~]# hostname
kevin_test [root@kevin_test ~]# cat haha.txt ; hostname
cat: haha.txt: No such file or directory
kevin_test
[root@kevin_test ~]# hostname ; cat haha.txt
kevin_test
cat: haha.txt: No such file or directory [root@kevin_test ~]# cat haha.txt || hostname
cat: haha.txt: No such file or directory
kevin_test
[root@kevin_test ~]# hostname || cat haha.txt
kevin_test [root@kevin_test ~]# cat haha.txt && hostname
cat: haha.txt: No such file or directory
[root@kevin_test ~]# hostname && cat haha.txt
kevin_test
cat: haha.txt: No such file or directory
26)如何比较两个目录
在Linux系统里如何快速比较两个目录中的文件列表的差别,比如test1、test2两个目录,对两个目录中多出的文件、少掉的文件分别做处理。基于运维日常中常用的方法,总结如下: 首先比较下两个目录的结构:
[root@ss-server ~]# yum install -y tree
[root@ss-server opt]# tree test1 test2
test1
├── a.txt
├── b.txt
└── haha
└── test.txt
test2
├── a.txt
├── b.txt
└── haha
├── bo.txt
└── test.txt 2 directories, 7 files 一、命令行输出的结果 ################################################################################################# 方法1:使用diff命令 -----------------------------------------------------------------
[root@ss-server ~]# cd /opt/
[root@ss-server opt]# diff -r test1 test2
diff -r test1/a.txt test2/a.txt
1a2
> hhhhh # 该行内容是test2/a.txt文件比test1/a.txt文件多出来的内容"
diff -r test1/b.txt test2/b.txt
1c1,2
< abcdfg # 该行是test1/b.txt文件内容
---
> 66666 # 这两行是test2/b.txt文件内容。这两个文件内容各不相同
> asdfsafd
Only in test2/haha: bo.txt # test2/haha目录相比如test1/haha目录多处一个bo.txt文件。
# 另外,test1/haha和test2/haha两个目录下的test.txt文件内容相同。diff命令只输出不同的,相同的不输出。 需要注意:diff命令会对两个每个文件中的每一行都做比较,所以文件较多或者文件较大的时候会非常慢。请谨慎使用 方法2:使用diff结合tree -----------------------------------------------------------------
[root@ss-server opt]# diff <(tree -Ci --noreport /opt/test1) <(tree -Ci --noreport /opt/test2)
1c1
< /opt/test1
---
> /opt/test2
4a5
> bo.txt #/opt/test2目录比/opt/test1目录多处一个bo.txt文件
# 该方法比较的只是两个目录下多处的文件。 说明:
tree的-C选项是输出颜色,如果只是看一下目录的不同,可以使用该选项,但在结合其他命令使用的时候建议不要使用该选项,因为颜色也会转换为对应的编码而输出;
-i是不缩进,建议不要省略-i,否则diff的结果很难看,也不好继续后续的文件操作;
--noreport是不输出报告结果,建议不要省略该选项。
该方法效率很高!!! 方法3:find结合diff -----------------------------------------------------------------
[root@ss-server opt]# find /opt/test1 -printf "%P\n" | sort > file1_diff.txt
[root@ss-server opt]# find /opt/test2 -printf "%P\n" | sort | sort | diff file1_diff.txt -
4a5
> haha/bo.txt 说明:
< 代表的是第一个目录/opt/test1中有,而第二个目录/opt/test2中没有的文件
> 则相反,代表的是第二个目录/opt/test2中有而第一个目录/opt/test1中没有。 不要省略-printf "%P\n",此处的%P表示find的结果中去掉前缀路径。
例如/opt/test2目录下多出了haha/bo.txt文件,所以结果显示的是haha/bo.txt,将前缀路径/opt/test2去掉了!
这样效率很高,输出也简洁! 如果不想使用-printf,那么先进入各目录再find也是可以的。如下:
[root@ss-server opt]# (cd /opt/test1;find . | sort >/tmp/file1.txt)
[root@ss-server opt]# (cd /opt/test2;find . | sort | diff /tmp/file1.txt -)
4a5
> ./haha/bo.txt 上面将命令放进括号中执行是为了在子shell中切换目录,不用影响当前所在目录。 方法4:使用rsync ------------------------------------------------------------------------
[root@ss-server opt]# rsync -rvn --delete /opt/test1/ /opt/test2 | sed -n '2,/^$/{/^$/!p}'
a.txt
b.txt
deleting haha/bo.txt
haha/test.txt 其中deleting所在的行就是第二个目录/opt/test2中多出的文件。
其他的都是两个目录中相同文件名的文件。 如果想区分出不同的是目录还是文件。可以加上"-i"选项。
[root@ss-server opt]# rsync -rvn -i --delete /opt/test1/ /opt/test2 | sed -n '2,/^$/{/^$/!p}'
>f.sT...... a.txt
>f.sT...... b.txt
*deleting haha/bo.txt
>f..T...... haha/test.txt 其中>f+++++++++中的f代表的是文件,d代表的目录。 需要注意上面的rsync比较目录的命令中有几点要说明:
1)一定不能缺少-n选项,它表示:尝试着进行rsync同步,但不会真的同步。
2)第一个目录(/opt/test1/)后一定不能缺少斜线,否则表示将/opt/test1整个目录同步到/opt/test2目录下。
3)其它选项,如"-r -v --delete"也都不能缺少,它们的含义很简单,分别表示递归、打印详细信息、同步前删除(只是模拟rsync操作,不会真的执行)
4)sed的作用是过滤掉和文件不相关的内容。
5)以上rsync命令是假定了比较两个目录中只有普通文件和目录,没有软链接、块设备等特殊文件。如果有,请考虑加上对应的选项或者使用-a替代-r,
否则结果中将出现skipping non-regular file的提示。但请注意,如果有软链接,且加了对应选项(-l或-a或其他相关选项),则可能会出现fileA-->fileB的输出。
6)这种方式效率很高,因为rsync的原因,筛选的可定制性也非常强。 二、图形化的比较结果 ################################################################################################# 方法1:使用vimdiff ---------------------------------------------------------------------
vimdiff命令用于快速比较和合并少量文件,详细用法参考:https://man.linuxde.net/vimdiff [root@ss-server opt]# vimdiff <(cd /opt/test1; find . | sort) <(cd /opt/test2; find . | sort)
或者
[root@ss-server ~]# vimdiff <(find /opt/test1 -printf "%P\n"| sort) <(find /opt/test2 -printf "%P\n"| sort) 如何从图形中退出??
依次按:Shift + 冒号,输入quit,回车; 再接着输入依次Shift + 冒号,输入quit,回车。 以上两次操作后,就退出图形了。 方法2:使用meld ---------------------------------------------------------------------
meld是python写的一个图形化文件/目录比较工具,所以必须先安装Linux图形界面或设置好图形界面接受协议。
它的功能非常丰富,和win下的beyond compare有异曲同工之妙。
meld是一个很酷的图形化工具(一个 GNOME 桌面下的可视化的比较和合并工具),可供那些喜欢使用鼠标的人使用,可按如下来安装。 [root@ss-server ~]# yum install -y meld 安装了meld之后,就可以在linux桌面上使用meld比较两个目录了,功能非常强大。这里就不做介绍了~
27)Shell中判断传入的变量是否为空? ( 使用 if [ X$1 == X ] )("== 和 = ")("()和{}")
[root@ss-server ~]# cat test.sh
#!/bin/bash
Deploy_Env=$1
Deploy_Env=`echo ${Deploy_Env} | tr '[a-z]' '[A-Z]'`
echo ${Deploy_Env}
if [[ x${Deploy_Env} == x ]];then
echo "变量参数为空"
exit 0
fi
[root@ss-server ~]# sh test.sh aa
AA
[root@ss-server ~]# sh test.sh 变量参数为空
[root@ss-server ~]# 注意: 上面test.sh脚本中的"==" 也可以写成 "=" 这里需要说明下
===========================================================
1)== 和 = 的区别
== 可用于判断变量是否相等
= 除了可用于判断变量是否相等外,还可以表示赋值。 在 [ ] 或 [[ ]] 中,= 与 == 都表示判断(字符串比较),此种情况下二者是等价的!
例如:
[root@ss-server ~]# a=beijing
[root@ss-server ~]# b=shanghai
[root@ss-server ~]# [ $a=$b ] && echo "equal"
equal
[root@ss-server ~]# [ $a==$b ] && echo "equal"
equal
[root@ss-server ~]# [[ $a=$b ]] && echo "equal"
equal
[root@ss-server ~]# [[ $a==$b ]] && echo "equal"
equal 在 (( )) 中 = 表示赋值, == 表示判断(整数比较),此种情况下二者是不等价的!
例如:
[root@ss-server ~]# ((n=5))
[root@ss-server ~]# echo $n
5
[root@ss-server ~]# ((n==5)) && echo "equal"
equal ===========================================================
2)()和{} 区别
()和{}都是对一串的命令进行执行,但有所区别: 相同点:
()和{}都是把一串的命令放在括号里面,并且命令之间用;号隔开 不同点:
()只是对一串命令重新开一个子shell进行执行,{}对一串命令在当前shell执行。
()最后一个命令可以不用分号,{}最后一个命令要用分号。
()里的第一个命令和左边括号不必有空格,{}的第一个命令和左括号之间必须要有一个空格!!!
()和{}中括号里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里的所有命令。 示例如下:
[root@ss-server ~]# var=test
[root@ss-server ~]# echo $var
test
[root@ss-server ~]# (var=notest;echo $var)
notest
[root@ss-server ~]# echo $var
test
[root@ss-server ~]# { var=notest;echo $var;}
notest
[root@ss-server ~]# echo $var
notest 有上面可知:
在{}中 第一个命令和{之间必须有空格,结束必须有;分号!!
{}中的修改了$var的值,说明在当前shell执行!! [root@ss-server ~]# { var1=test1;var2=test2;echo $var1>a;echo $var2;}
test2
[root@ss-server ~]# cat a
test1
[root@ss-server ~]# { var1=test1;var2=test2;echo $var1;echo $var2;}>a
[root@ss-server ~]# cat a
test1
test2 脚本如下:
[root@ss-server ~]# cat test.sh
#!/bin/bash
(
echo "1"
echo "2"
) | awk '{print NR,$0}'
[root@ss-server ~]# sh test.sh
1 1
2 2
28)eval 命令用法
eval可读取一连串的参数,然后再依参数本身的特性来执行。eval是shell内建命令,可用shell查看其用法。参数不限数目,彼此之间用分号隔开。 eval [参数]
eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令。
该命令适用于那些一次扫描无法实现其功能的变量。该命令对变量进行两次扫描。这些需要进行两次扫描的变量有时被称为复杂变量。
不过这些变量本身并不复杂。eval命令也可以用于回显简单变量,不一定是复杂变量。 示例1: eval命令也可以用于回显简单变量,不一定是复杂变量 ##########################################################################
[root@localhost ~]# NAME=kevin
[root@localhost ~]# echo ${NAME}
kevin
[root@localhost ~]# eval echo ${NAME}
kevin
[root@localhost ~]# echo '${'"NAME"'}'
${NAME}
[root@localhost ~]# eval echo '${'"NAME"'}'
kevin [root@localhost ~]# a=123
[root@localhost ~]# echo ${a}
123
[root@localhost ~]# eval echo ${a}
123
[root@localhost ~]# echo '${a}' #单引号默认不识别变量
${a}
[root@localhost ~]# eval echo '${a}' #使用eval后,用户回显变量,则单引号里面的变量就会被显示出来
123
[root@localhost ~]# echo "${a}" #双引号默认识别变量
123
[root@localhost ~]# eval echo "${a}"
123 示例2:执行含有字符串的命令 ##########################################################################
首先我们首先创建一个名为test的小文件,在这个小文件中含有一些文本。
接着,将cat test赋给变量myfile,现在我们e c h o该变量,看看是否能够执行上述命令。
[root@localhost ~]# cat test
Hello World!!!
I am a chinese Boy! 将"cat test"赋给变量myfile
[root@localhost ~]# myfile="cat test" 如果直接echo该变量,那么将无法列出test文件中的内容。
[root@localhost ~]# echo $myfile
cat test 接着来试一下eval命令,记住eval命令将会对该变量进行两次扫瞄。
[root@localhost ~]# eval $myfile
Hello World!!!
I am a chinese Boy! 从上面的结果可以看出,使用e v a l命令不但可以置换该变量,还能够执行相应的命令。第
一次扫描进行了变量置换,第二次扫描执行了该字符串中所包含的命令cat test。 示例3: eval可以用来显示出传递给脚本的最后一个参数 ##########################################################################
下面提及的命令是eval其中一个很普通的应用,它重复了1次命令行参数传递过程,纯粹地执行命令的命令。
[root@localhost ~]# echo 'eval echo \$$#' > test
[root@localhost ~]# cat test
eval echo \$$#
[root@localhost ~]# sh test aa bb cc
cc [root@localhost ~]# cat test.sh
#!/bin/bash
echo "Total of the arguments passed $#"
echo "The process Id is $$"
echo "Last argument os "$(eval echo \$$#)""
[root@localhost ~]# sh test.sh beijing shanghai anhui
Total of the arguments passed 3
The process Id is 82540
Last argument os anhui 在上面的脚本中,eval命令首先把$# 解析为当前shell的参数个数,然后再进行第二次扫描时得出最后一个参数。 示例4:给每个值一个变量名 ##########################################################################
可以给一个值一个变量名。下面会对此做些解释,假定有一个名为test2的文件:
[root@localhost ~]# cat test2
COMMANY TQ
LANGUE ENGLISH
LIKE YES 希望该文件中的第一列成为变量名,第二列成为该变量的值,这样就可以:
[root@localhost ~]# cat test.sh
#!/bin/bash
while read NAME VALUE
do
eval "${NAME}=${VALUE}"
done <test2
echo "$COMMANY $LANGUE $LIKE"
[root@localhost ~]# sh test.sh
TQ ENGLISH YES 示例5:使用eval命令进行1次命令行参数传递 ##########################################################################
[root@localhost ~]# cat test.sh
#!/bin/bash
NODE_IP_LIST=$1
NODE_PORT_LIST=$2
for ((i=1;i<=3;i++)); do
eval NODE_IP='`echo ${NODE_IP_LIST}|awk -F, "{ print $"$i" }"`' #这里awk语句中的print后面{}两边之所以加双引号而不是单引号,是因为要将$i变量识别出来!!!
eval NODE_PORT='`echo ${NODE_PORT_LIST}|awk -F, "{ print $"$i" }"`' #如果awk语句中的print后面{}两边加单引号,则$i变量就识别不出来了!!! echo "address is ${NODE_IP}:${NODE_PORT}"
done [root@localhost ~]# sh test.sh 172.16.60.21,172.16.60.22,172.16.60.23 8080,8081,8082
address is 172.16.60.21:8080
address is 172.16.60.22:8081
address is 172.16.60.23:8082 如果上面test.sh脚本中不使用eval,将eval去掉的话,则命令行参数就传递失败了
[root@localhost ~]# cat test.sh
#!/bin/bash
NODE_IP_LIST=$1
NODE_PORT_LIST=$2
for ((i=1;i<=3;i++)); do
NODE_IP='`echo ${NODE_IP_LIST}|awk -F, "{ print $"$i" }"`'
NODE_PORT='`echo ${NODE_PORT_LIST}|awk -F, "{ print $"$i" }"`' echo "address is ${NODE_IP}:${NODE_PORT}"
done [root@localhost ~]# sh test.sh 172.16.60.21,172.16.60.22,172.16.60.23 8080,8081,8082
address is `echo ${NODE_IP_LIST}|awk -F, "{ print $"$i" }"`:`echo ${NODE_PORT_LIST}|awk -F, "{ print $"$i" }"`
address is `echo ${NODE_IP_LIST}|awk -F, "{ print $"$i" }"`:`echo ${NODE_PORT_LIST}|awk -F, "{ print $"$i" }"`
address is `echo ${NODE_IP_LIST}|awk -F, "{ print $"$i" }"`:`echo ${NODE_PORT_LIST}|awk -F, "{ print $"$i" }"` 将NODE_IP和NODE_PORT两个参数变量后面的单引号去掉,则效果和使用了eval命令一样
[root@localhost ~]# cat test.sh
#!/bin/bash
NODE_IP_LIST=$1
NODE_PORT_LIST=$2
for ((i=1;i<=3;i++)); do
NODE_IP=`echo ${NODE_IP_LIST}|awk -F, "{ print $"$i" }"` #这里awk语句中的print后面{}两边之所以加双引号而不是单引号,是因为要将$i变量识别出来!!!
NODE_PORT=`echo ${NODE_PORT_LIST}|awk -F, "{ print $"$i" }"` #如果awk语句中的print后面{}两边加单引号,则$i变量就识别不出来了!!! echo "address is ${NODE_IP}:${NODE_PORT}"
done [root@localhost ~]# sh test.sh 172.16.60.21,172.16.60.22,172.16.60.23 8080,8081,8082
address is 172.16.60.21:8080
address is 172.16.60.22:8081
address is 172.16.60.23:8082 ##########################################################################################################################
需要注意一个细节:
下面两种方式是一样的效果,即awk中-F后面的分隔符两边加不加引号,加双引号还是单引号,都不影响分割的效果!!!
但是后面print的{}两边必须是单引号!!!
awk -F"分隔符" '{print $n}' filename
awk -F'分隔符' '{print $n}' filename
awk -F分隔符 '{print $n}' filename [root@localhost ~]# echo 172.16.60.21,172.16.60.22,172.16.60.23|awk -F"," '{ print $1 }'
172.16.60.21
[root@localhost ~]# echo 172.16.60.21,172.16.60.22,172.16.60.23|awk -F, '{ print $1 }'
172.16.60.21 下面两种方式均是不正确的。直接将$1作为前面echo输出的整体了,即-F后面的分隔符没有起作用!
[root@localhost ~]# echo 172.16.60.21,172.16.60.22,172.16.60.23|awk -F, "{ print $1 }"
172.16.60.21,172.16.60.22,172.16.60.23
[root@localhost ~]# echo 172.16.60.21,172.16.60.22,172.16.60.23|awk -F"," "{ print $1 }"
172.16.60.21,172.16.60.22,172.16.60.23 下面表达方式也是不正确的。$1两边加双引号,直接将$1打印出来了
[root@localhost ~]# echo 172.16.60.21,172.16.60.22,172.16.60.23|awk -F, '{ print "$1" }'
$1
[root@localhost ~]# echo 172.16.60.21,172.16.60.22,172.16.60.23|awk -F"," '{ print "$1" }'
$1
29)shell判断传入的便利是否为空 if [ x$1 = x ]
if语句中使用"x$1 = x"来判断$1传入参数是否为空。
如果x$1等于x,则$1传入参数为空。
如果x$1不等于x,则$1传入参数不为空。 #################### 注意 ####################
x要么两边都是小写,要么两边都是大写!
等号可以是"=",也可以使用"=="
############################################### 如下脚本配置,如果x${num}的值为x,则$num传入的变量为空!
[root@localhost ~]# cat test.sh
#!/bin/bash
num=$1
if [ x${num} = x ];then
echo "the num argu is empty!"
else
echo "the num args is $1"
fi
[root@localhost ~]# sh test.sh
the num argu is empty!
[root@localhost ~]# sh test.sh beijing
the num args is beijing [root@localhost ~]# cat test.sh
#!/bin/bash
num=$1
if [ X${num} = X ];then
echo "the num argu is empty!"
else
echo "the num args is $1"
fi
[root@localhost ~]# sh test.sh
the num argu is empty!
[root@localhost ~]# sh test.sh shanghai
the num args is shanghai [root@localhost ~]# cat test.sh
#!/bin/bash
num=$1
if [ X${num} == X ];then
echo "the num argu is empty!"
else
echo "the num args is $1"
fi
[root@localhost ~]# sh test.sh
the num argu is empty!
[root@localhost ~]# sh test.sh shenzheng
the num args is shenzheng
30)set 命令用法
set命令是 Bash 脚本的重要环节,却常常被忽视,导致脚本的安全性和可维护性出问题。set命令用来修改 Shell 环境的运行参数,也就是可以定制环境。set一共有十几个参数可以定制,官方手册有完整清单,这里重点介绍其中最常用的几个参数。
1)set -e 参数
========================================================================================
set -e:表示执行的时候如果出现了返回值为非零,整个脚本就会立即退出。
set +e:表示执行的时候如果出现了返回值为非零,将会继续执行下面的脚本。 即"set +e"表示关闭-e选项,"set -e"表示重新打开-e选项。 "set -e"命令作用
对于编写的每个脚本,都应该在文件开头加上set -e,这句语句的作用是告诉bash,如果任何语句的执行结果不是true则应该退出。
这样的好处是防止错误像滚雪球般变大导致一个致命的错误,而这些错误本应该在之前就被处理掉。
如果要增加可读性,可以使用set -o errexit,它的作用与set -e相同。 "set -e"命令用法总结:
1. 当命令的返回值为非零状态时,则立即退出脚本的执行。
2. 作用范围仅仅只限于脚本执行的当前进行,不作用于其创建的子进程!比如在当前终端下设置"set -e", 但是关闭该窗口,另开一个终端窗口,之前设置的"set -e"功能就失效了!
3. 另外,当想根据命令执行的返回值,输出对应的log时,最好不要采用set -e选项,而是通过配合exit 命令来达到输出log并退出执行的目的。 示例如下:
执行"set -e"之后,在接下来执行的命令中,如果命令的返回值不为0,那么会使所在的进程或shell退出。 示例1:
查看haha.txt文件,由于该文件不存在,之后命令后的返回值不为0
由于没有提前执行"set -e",则命令执行后不会退出该进程
[root@ss-server ~]# cat haha.txt
cat: haha.txt: No such file or directory
[root@ss-server ~]# echo $?
1
[root@ss-server ~]# 现在执行"set -e"
[root@ss-server ~]# set -e
[root@ss-server ~]# cat haha.txt
cat: haha.txt: No such file or directory #由于在之前添加了"set -e",则命令返回值为非零时就自动退出。 如果将"set -e"换成"set +e",则命令执行后返回值为非零,将不会自动退出shell,会继续执行。
[root@ss-server ~]# set +e
[root@ss-server ~]# cat haha.txt
cat: haha.txt: No such file or directory
[root@ss-server ~]# echo $?
1
[root@ss-server ~]# 为了增加可读性,可以使用"set -o errexit"命令来替换"set -e",两者效果一样!
[root@ss-server ~]# set -o errexit
[root@ss-server ~]# cat haha.txt
cat: haha.txt: No such file or directory #执行命令的返回值为非零,直接退出当前shell。 示例2:
[root@ss-server ~]# cat hehe.txt;hostname
cat: hehe.txt: No such file or directory
ss-server [root@ss-server ~]# set -e
[root@ss-server ~]# cat hehe.txt;hostname
cat: hehe.txt: No such file or directory #执行命令的返回值为非零,直接退出当前shell。 [root@ss-server ~]# set -o errexit
[root@ss-server ~]# cat hehe.txt;hostname
cat: hehe.txt: No such file or directory #执行命令的返回值为非零,直接退出当前shell。 ############### 需要注意 ###############
1. "set -e"参数 和 "set -o errexit" 两者等同!上面已有示例说明。
2. 还有一种方法是使用command || true,使得该命令即使执行失败,脚本也不会终止执行。这个需要特别注意下! 如下,虽然设置了"set -e"参数,并且"cat hehe.txt"执行命令的返回值为非零。但是由于使用了||符号,表示前面命令执行结果为false后,继续执行后面的命令。
那么只要这个||后面的命令执行结果为true,则整个命令执行结果返回值就是0,所以即使设置了"set -e",也没有退出当前shell! 示例如下:
[root@ss-server ~]# set -e
[root@ss-server ~]# cat hehe.txt || hostname
cat: hehe.txt: No such file or directory
ss-server
[root@ss-server ~]# echo $?
0 [root@ss-server ~]# set -e
[root@ss-server ~]# cat hehe.txt || cat haha.txt || hostname
cat: hehe.txt: No such file or directory
cat: haha.txt: No such file or directory
ss-server 如果||最后面的那条命令执行结果为false,则整个命令执行结果返回值就是非零,则就会退出当前shell
[root@ss-server ~]# set -e
[root@ss-server ~]# cat hehe.txt || cat haha.txt
cat: hehe.txt: No such file or directory
cat: haha.txt: No such file or directory 3. 还要注意一种例外情况,就是set -e不适用于管道命令。 所谓管道命令,就是多个子命令通过管道运算符(|)组合成为一个大的命令。Bash 会把最后一个子命令的返回值,作为整个命令的返回值。
也就是说,只要最后一个子命令不失败,管道命令总是会执行成功,因此它后面命令依然会执行,set -e就失效了。 示例如下:
[root@ss-server ~]# cat test.sh
#!/bin/bash
set -e
cat haha_yu | echo "hello world"
hostname 执行结果:
[root@ss-server ~]# sh test.sh
hello world
cat: haha_yu: No such file or directory
ss-server 上面脚本中,虽然haha文件不存在,但是cat haha_yu | echo "hello world"它是一个整体命令,只有|后面的命令执行成功,则整个命令的返回值就是0
所以后面的"hostname"命令也会继续执行。 2)set -o pipefail 参数
========================================================================================
针对上面set -e不适用于管道命令的例子,set -o pipefail 用来解决这种情况,只要一个子命令失败,整个管道命令就失败,脚本就会终止执行。 set -o pipefail表示在管道连接的命令序列中,只要有任何一个命令返回非0值,则"整个管道命令"返回非0值,即使最后一个命令返回0!! 示例如下:
[root@ss-server ~]# cat test.sh
#!/bin/bash
set -eo pipefail
cat haha_yu | echo "hello world"
hostname 执行结果如下:
[root@ss-server ~]# sh test.sh
hello world
cat: haha_yu: No such file or directory 示例2:
|管道命令,只要最后一个命令执行成功,则整个管道命令执行结果返回值就是0,即整个管道命令执行就算成功!
[root@ss-server ~]# cat haha_yu | echo "hello world"
hello world
cat: haha_yu: No such file or directory
[root@ss-server ~]# echo $?
0
[root@ss-server ~]# cat haha_yu | echo "hello world" >/dev/null 2>&1
cat: haha_yu: No such file or directory
[root@ss-server ~]# echo $?
0 设置了"set -o pipefail"之后,只要有任何一个命令返回非0值,则"整个管道命令"返回非0值,即使最后一个命令返回0!
[root@ss-server ~]# set -o pipefail
[root@ss-server ~]# cat haha_yu | echo "hello world" >/dev/null 2>&1
cat: haha_yu: No such file or directory
[root@ss-server ~]# echo $?
1 3)set -u 参数
========================================================================================
该参数表示在脚本执行中,如遇到不存在的变量就会报错,并停止执行! 示例如下:
[root@ss-server ~]# cat test.sh
#!/bin/bash
echo ${a}
echo `hostname` 上面脚本中,${a}是一个不存在的变量。执行结果如下:
[root@ss-server ~]# sh test.sh ss-server 可以看到,echo ${a}输出了一个空行,说明Bash忽略了不存在的${a}变量,然后继续执行echo `hostname`。
大多数情况下,这不是我们想要的行为,遇到变量不存在,脚本应该报错,而不是一声不响地往下执行。
那么"set -u"参数就用来改变这种行为。脚本在头部加上它,遇到不存在的变量就会报错,并停止执行。 [root@ss-server ~]# cat test.sh
#!/bin/bash
set -u
echo ${a}
echo `hostname` 执行结果如下:
[root@ss-server ~]# sh test.sh
test.sh: line 3: a: unbound variable 从上面可以看到,添加"set -u"参数后,脚本执行中发现不存在${a}变量就报错了(报错"未绑定的变量"),并且不再执行后面的语句。 需要注意:
"set -u" 还有另一种写法"set -o nounset",两者是等价的!!! [root@ss-server ~]# cat test.sh
#!/bin/bash
set -o nounset
echo ${a}
echo `hostname` [root@ss-server ~]# sh test.sh
test.sh: line 3: a: unbound variable 4)set -x 参数
========================================================================================
默认情况下,shell脚本执行后,屏幕只显示运行结果,没有其他内容。
如果多个命令连续执行,它们的运行结果就会连续输出。有时会分不清,某一段内容是什么命令产生的。 "set -x"参数用来在运行结果之前,先输出执行的那一行命令。即输出脚本执行的详细过程! 示例如下:
[root@ss-server ~]# cat test.sh
#!/bin/bash
DATE=$(date +%Y%m%d)
echo "$(hostname) and ${DATE}" 执行结果如下,只输出运行结果,没有输出详细的执行命令
[root@ss-server ~]# sh test.sh
ss-server and 20191218 现在加上"set -x"参数
[root@ss-server ~]# cat test.sh
#!/bin/bash
set -x
DATE=$(date +%Y%m%d)
echo "$(hostname) and ${DATE}" 执行结果如下:
[root@ss-server ~]# sh test.sh
++ date +%Y%m%d
+ DATE=20191218
++ hostname
+ echo 'ss-server and 20191218'
ss-server and 20191218 需要注意:
"set -x"参数还有另一种写法"set -o xtrace",两者是等价的!!!
[root@ss-server ~]# cat test.sh
#!/bin/bash
set -o xtrace
DATE=$(date +%Y%m%d)
echo "$(hostname) and ${DATE}" 执行结果如下:
[root@ss-server ~]# sh test.sh
++ date +%Y%m%d
+ DATE=20191218
++ hostname
+ echo 'ss-server and 20191218'
ss-server and 20191218 其实,上面"set -x" 和 "set -o xtrace" 作用就是打印脚本执行的详细过程,这和"sh -x xxx.sh"的效果也是一样的!
[root@ss-server ~]# cat test.sh
#!/bin/bash
DATE=$(date +%Y%m%d)
echo "$(hostname) and ${DATE}" 如上,脚本中没有添加"set -x" 或 "set -o xtrace", 在执行脚本时使用"sh -x"也可以打印脚本执行过程。
[root@ss-server ~]# sh -x test.sh
++ date +%Y%m%d
+ DATE=20191218
++ hostname
+ echo 'ss-server and 20191218'
ss-server and 20191218 5)shell脚本的错误处理
========================================================================================
如果脚本里面有运行失败的命令(返回值非0),Bash 默认会继续执行后面的命令。
[root@ss-server ~]# cat test.sh
#!/bin/bash
cat haha_yu
echo `hostname` 上面脚本中,"cat haha_yu"是一个执行会报错的命令,因为haha_yu文件不存在。
但是,Bash 会忽略这个错误,继续往下执行。
[root@ss-server ~]# sh test.sh
cat: haha_yu: No such file or directory
ss-server 可以看到,上面脚本中Bash 只是显示有错误,并没有终止执行。
这种行为很不利于脚本安全和除错。实际开发中,如果某个命令失败,往往需要脚本停止执行,防止错误累积。这时,一般采用下面的写法。
"command || exit 1" 上面的写法表示只要command有非零返回值,脚本就会停止执行。 如果停止执行之前需要完成多个操作,就要采用下面三种写法。
# 写法一
command || { echo "command failed"; exit 1; } # 写法二
if ! command; then echo "command failed"; exit 1; fi # 写法三
command
if [ "$?" -ne 0 ]; then echo "command failed"; exit 1; fi 另外,除了停止执行,还有一种情况:
如果两个命令有继承关系,只有第一个命令成功了,才能继续执行第二个命令,那么就要采用下面的写法。
command1 && command2 至于,;、||、&& 这三者的使用区别,在上面已经详细介绍过了,这里就不赘述了。 示例1
[root@ss-server ~]# cat test.sh
#!/bin/bash
cat haha_yu || exit 1
echo `hostname` 执行结果如下:
[root@ss-server ~]# sh test.sh
cat: haha_yu: No such file or directory 示例2
[root@ss-server ~]# cat test.sh
#!/bin/bash
cat haha_yu || { echo "执行失败";exit 1;}
echo `hostname` 执行结果如下:
[root@ss-server ~]# sh test.sh
cat: haha_yu: No such file or directory
执行失败 示例3
[root@ss-server ~]# cat test.sh
#!/bin/bash
if ! cat haha_yu;then
echo "执行失败"
exit 1
fi
echo `hostname` 执行结果如下:
[root@ss-server ~]# sh test.sh
cat: haha_yu: No such file or directory
执行失败 示例4
[root@ss-server ~]# cat test.sh
#!/bin/bash
cat haha_yu
if [ $? -ne 0 ];then
echo "执行失败"
exit 1
fi
echo `hostname` 执行结果如下:
[root@ss-server ~]# sh test.sh
cat: haha_yu: No such file or directory
执行失败 6)set命令总结
========================================================================================
set命令的上面这四个参数,一般都放在一起在shell脚本中使用。 # 写法一
set -euxo pipefail # 写法二
set -eux
set -o pipefail 以上这两种写法建议放在所有 Bash 脚本的头部。 还有另一种办法:在执行Bash脚本的时候,从命令行传入这些参数。
# bash -euxo pipefail script.sh
Shell脚本字符串匹配及日常命令工具 - 用法总结(技巧指南)的更多相关文章
- linux C程序中获取shell脚本输出(如获取system命令输出)
转载自 http://blog.csdn.net/hjxhjh/article/details/7909518 1. 前言 Unix 界有一句名言:“一行shell脚本胜过万行C程序”,虽然这句话有些 ...
- Linux Shell脚本入门--cut命令
Linux Shell脚本入门--cut命令 cut cut 命令可以从一个文本文件或者文本流中提取文本列. cut语法 [root@www ~]# cut -d'分隔字符' -f fields &l ...
- Linux Shell脚本入门--wget 命令用法详解
Linux Shell脚本入门--wget 命令用法详解 wget是在Linux下开发的开放源代码的软件,作者是Hrvoje Niksic,后来被移植到包括Windows在内的各个平台上.它有以下功能 ...
- shell脚本基础和grep文本处理工具企业应用2
shell脚本编程: 编程语言的分类: 根据运行方式 编译运行:源代码-->编译器(编译)-->程序文件 优 ...
- shell脚本中判断上一个命令是否执行成功
shell脚本中判断上一个命令是否执行成功 shell中使用符号“$?”来显示上一条命令执行的返回值,如果为0则代表执行成功,其他表示失败.结合if-else语句实现判断上一个命令是否执行成功. 示例 ...
- [shell]上一个命令执行完成,才执行下一个操作 | shell脚本中判断上一个命令是否执行成功
shell脚本中判断上一个命令是否执行成功 shell中使用符号“$?”来显示上一条命令执行的返回值,如果为0则代表执行成功,其他表示失败.结合if-else语句实现判断上一个命令是否执行成功. 场 ...
- shell脚本编程-使用结构化命令(if/else)(转)
11.1 使用if-then语句 格式如下 if语句会执行if行定义的那个命令,如果该命令的退出状态码是0,则then部分的语句就会执行,其他值,则不会 1 2 3 4 if command th ...
- Linux Shell脚本编程--curl命令详解
用途说明 curl命令是一个功能强大的网络工具,它能够通过http.ftp等方式下载文件,也能够上传文件.其实curl远不止前面所说的那些功能,大家可以通过man curl阅读手册页获取更多的信息.类 ...
- Shell脚本基础及基本常用命令
1.概述 脚本语言(shell.python):解释性语言,用解释器解释 运行效率低 | c.java:描述性语言,运行效率高 以.sh结尾会有高亮显示 执行: sh hello.sh 或者 chmo ...
随机推荐
- antd 用 customize-cra 方式引入 sass
antd 用 customize-cra 方式引入 sass 只需要安装:node-sass 即可
- 【计算机视觉】基于OpenCV的人脸识别
一点背景知识 OpenCV 是一个开源的计算机视觉和机器学习库.它包含成千上万优化过的算法,为各种计算机视觉应用提供了一个通用工具包.根据这个项目的关于页面,OpenCV 已被广泛运用在各种项目上,从 ...
- 高级UI-TableLayout
TableLayout选项卡,用于需要使用选项卡的场景,一般是用于切换Fragment,现在的主流做法一般是TableLayout+ViewPager+Fragment,综合实现选项卡的操作 由于Ta ...
- Flask项目中使用mysql数据库启动项目是发出警告
Flask项目中使用mysql数据库启动项目是发出警告: Warning: (1366, "Incorrect string value: '\xD6\xD0\xB9\xFA\xB1\xEA ...
- Python 常用包收集
转自:http://www.cnblogs.com/Logic0/archive/2010/09/03/1850382.html 常用的自带类库 常用的外部类库 Tkinter———— P ...
- nginx location 路由的几个配置纪要
1:网上没有查到在线测试 nginx location 规则的网址 在服务器上可以通过 return 返回测试比如 把#号去掉 # location /admin\.php(.*) # { #def ...
- linux环境下编写shell脚本实现启动停止tomcat服务
第一步:以管理员的身份进入控制台,在指定目录下新建一个shell脚本,我这里命名为tomcat.sh 第二步:编写shell脚本 #!/bin/bash tomcat_home=/usr/tomcat ...
- Cortex_m7内核cache深入了解和应用
一,cache概述 从下图可以看出,从M7内核才开始有的cache,这对于从M0,M3,M4一路走来的小伙伴来说,多了一个cache就多了一个障碍. Cortex-M7 core with 32K/3 ...
- beego入门笔记
Beego Learn Note 示例环境在Deepin系统下. deepin 15.9.3 ├── Beego : 1.11.2 ├── GoVersion : go1.12.4 ├── GOOS ...
- QT-入门:创建项目时遇到工程工具集(Kit)找不到问题
创建项目遇到了以下提示: Please add a kit in the options or via the maintenance tool of the SDK 解决方法: 在指定的工具链中设置 ...