Shell脚本中常用的特殊符号 - 运维总结
# 井号
这几乎是个shell满场都有的符号,用在shell脚本的开头,如"#!/bin/bash" 井号也常出现在一行的开头,或者位于完整指令之后,这类情况表示符号后面的是注解文字,不会被执行。 由于这个特性,当临时不想执行某行指令时,只需在该行开头加上 # 就行了。这常用在撰写过程中。 如果被用在指令中,或者引号双引号括住的话,或者在倒斜线的后面,那他就变成一般符号,不具上述的特殊功能。
~ 用户家目录
算是个常见的符号,代表使用者的 home 目录:cd ~;也可以直接在符号后加上某帐户的名称:cd ~user或者当成是路径的一部份:~/bin
~+ 当前的工作目录,这个符号代表当前的工作目录,她和内建指令 pwd的作用是相同的。
[root@VM_16_9_centos ~]# pwd /root [root@VM_16_9_centos ~]# echo ~+/var/log /root/var/log
~- 上次的工作目录,这个符号代表上次的工作目录。
[root@VM_16_9_centos ~]# pwd /root [root@VM_16_9_centos ~]# echo ~+/var/log /root/var/log [root@VM_16_9_centos ~]# echo ~-/etc/httpd/logs /root/test/etc/httpd/logs
; 分号
在 shell 中,担任"连续指令"功能的符号就是"分号"。譬如以下的例子:
[root@VM_16_9_centos ~]# mkdir test;cd test;echo "safd" >test1;cat test1;pwd safd /root/test
;; 连续分号
专用在 case 的选项,担任 Terminator 的角色。
[root@localhost ~]# cat a.sh #!/bin/bash read -p "please write:" fop case ${fop} in help) echo "Usage: Command -help -version filename";; version) echo "version 0.1" ;; esac [root@localhost ~]# sh a.sh please write:help Usage: Command -help -version filename
. 点号 (dot,就是“点”)
在 shell 中,使用者应该都清楚,一个 dot 代表当前目录,两个 dot 代表上层目录。
[root@ss-server ~]# cd /usr/local/src/ [root@bz3aomsmsap1002 src]# cd ../ [root@bz3aomsmsap1002 local]# pwd /usr/local [root@ss-server ~]# cd /usr/local/src/ [root@bz3aomsmsap1002 src]# cd ../../ [root@bz3aomsmsap1002 usr]# pwd /usr
如果档案名以 dot 开头,该档案就属特殊档案,用 ls指令必须加-a 选项才会显示(即查看隐藏文件)。除此之外,在 regularexpression 中,一个 dot 代表匹配一个字元。
' ' 单引号 (single quote)
被单引号用括住的内容,将被视为单一字串。在引号内的代表变数的$符号,没有作用,也就是说,他被视为一般符号处理,防止任何变量替换。
[root@localhost ~]# heyyou=homeecho [root@localhost ~]# echo '$heyyou' $heyyou
" " 双引号 (double quote)
被双引号用括住的内容,将被视为单一字串。它防止通配符扩展,但允许变量扩展。这点与单引数的处理方式不同。
[root@VM_16_9_centos ~]# heyyou=homeecho [root@VM_16_9_centos ~]# echo ${heyyou} homeecho [root@VM_16_9_centos ~]# echo '${heyyou}' ${heyyou} [root@VM_16_9_centos ~]# echo "${heyyou}" homeecho
`` 倒引号,相当于$(),表示命令替换,将里面命令执行结果传给变量参数。
在前面的单双引号,括住的是字串,但如果该字串是一列命令列,会怎样?答案是不会执行。要处理这种情况,我们得用倒单引号``来做。
[root@VM_16_9_centos ~]# fdv=`date +%F` [root@VM_16_9_centos ~]# echo "Today $fdv" Today 2019-11-28
在倒引号内的 date +%F 会被视为指令,执行的结果会带入 fdv 变数中。
, 逗点 (标点中的逗号)
这个符号常运用在运算当中当做"区隔"用途。如下例:
[root@VM_16_9_centos ~]# cat a.sh #!/bin/bash let "t1 = ((a = 5 + 3, b = 7 - 1, c = 15 / 3))" echo "t1= $t1, a = $a, b = $b" [root@VM_16_9_centos ~]# sh a.sh t1= 5, a = 8, b = 6
/ 斜线
在路径表示时,代表目录。
[root@VM_16_9_centos ~]# cd /etc/rc.d [root@VM_16_9_centos rc.d]# cd ../.. [root@VM_16_9_centos /]#
通常单一的 / 代表 root 根目录的意思;在四则运算中,代表除法的符号。
[root@VM_16_9_centos ~]# let "num1 = ((a = 10 / 2, b = 25 / 5))" [root@VM_16_9_centos ~]# echo ${num1} 5
\\ 双倒斜线 和 \ 单倒斜线
\\ 双倒斜线:放在指令前,有取消 aliases的作用 ======================================= [root@localhost ~]# alias kevin="ls" [root@localhost ~]# kevin a anaconda-ks.cfg [root@localhost ~]# kevin -l total 4 -rw-r--r-- 1 root root 0 Nov 28 22:56 a -rw-------. 1 root root 1850 Oct 22 12:11 anaconda-ks.cfg [root@localhost ~]# \\kevin -bash: \kevin: command not found [root@localhost ~]# \\kevin -l -bash: \kevin: command not found \ 单倒斜线:放在特殊符号前,则该特殊符号的作用消失。即转义符号 ======================================= [root@VM_16_9_centos ~]# bkdir=/home [root@VM_16_9_centos ~]# echo "this is ${bkdir}" this is /home [root@VM_16_9_centos ~]# echo "this is \${bkdir}" this is ${bkdir} [root@VM_16_9_centos ~]# echo \"this is ${bkdir}\" "this is /home" [root@VM_16_9_centos ~]# echo \"this is \${bkdir}\" "this is ${bkdir}"
| 管道 (pipeline)
pipeline 是 Linux系统中基础且重要的观念。连结上个指令的标准输出,做为下个指令的标准输入。
[root@VM_16_9_centos ~]# who root pts/0 2019-11-28 22:49 (115.171.60.14) root pts/1 2019-11-28 23:01 (115.171.60.14) [root@VM_16_9_centos ~]# who | wc -l 2
善用这个观念,对精简 script 有相当的帮助。
! 惊叹号(negate or reverse)
通常它代表反逻辑的作用,譬如条件侦测中,用 != 来代表"不等于"
[root@VM_16_9_centos ~]# cat a.sh #!/bin/bash if [ "$?" != 0 ];then echo "Executes error" exit 1 fi [root@VM_16_9_centos ~]# sh a.sh "Executes error"
在规则表达式中她担任 "反逻辑" 的角色
[root@VM_16_9_centos ~]# touch bo{0,1,2,3,4,5,6,7,8,9} [root@VM_16_9_centos ~]# ls bo0 bo1 bo2 bo3 bo4 bo5 bo6 bo7 bo8 bo9 [root@VM_16_9_centos ~]# ls bo{0,1,2,3} bo0 bo1 bo2 bo3 [root@VM_16_9_centos ~]# ls bo[0-3] bo0 bo1 bo2 bo3 显示除了bo0-bo3之外的其他文件 [root@VM_16_9_centos ~]# ls bo[!0-3] bo4 bo5 bo6 bo7 bo8 bo9 显示除了bo5-bo8之外的其他文件 [root@VM_16_9_centos ~]# ls bo[!5-8] bo0 bo1 bo2 bo3 bo4 bo9
: 内奸指令
在 bash 中,这是一个内建指令:"什么事都不干",但返回状态值 0。
什么都不干,返回状态值 0 [root@VM_16_9_centos ~]# echo $? 0 [root@VM_16_9_centos ~]# : > a.txt 上面这一行,相当于 [root@VM_16_9_centos ~]# cat /dev/null >a.xtt 不仅写法简短了,而且执行效率也好上许多。
? 问号
在文件名扩展(Filename expansion)上扮演的角色是匹配一个任意的字元,但不包含 null 字元。
[root@VM_16_9_centos ~]# ls a12e.txt aae_txt agte.txt akte.txt aste.txt [root@VM_16_9_centos ~]# ls a?te.txt agte.txt akte.txt aste.txt [root@VM_16_9_centos ~]# ls a1?e.txt a12e.txt [root@VM_16_9_centos ~]# ls aae?txt aae_txt
善用她的特点,可以做比较精确的档名匹配。
* 任意个任意字符。任意的单个或多个字符
相当常用的符号。在文件名扩展(Filename expansion)上,她用来代表任何字元,包含 null 字元。
[root@VM_16_9_centos ~]# ls a12e.txt aae_txt agte.txt akte.txt a.sh aste.txt [root@VM_16_9_centos ~]# ls a*e.txt a12e.txt agte.txt akte.txt aste.txt [root@VM_16_9_centos ~]# ls a*te.txt agte.txt akte.txt aste.txt 在运算时,它则代表 "乘法"。 [root@VM_16_9_centos ~]# let "fmult=2*3" [root@VM_16_9_centos ~]# echo ${fmult} 6 除了内建指令 let,还有一个关于运算的指令expr,星号在这里也担任"乘法"的角色。不过在使用上得小心,他的前面必须加上escape字元(即转义符)。 [root@VM_16_9_centos ~]# expr 2 \* 3 6
** 次方运算
[root@ss-server ~]# let sum=2**4 [root@ss-server ~]# echo ${sum} 16 [root@ss-server ~]# echo $((3*3)) 9 [root@ss-server ~]# let sum=2**4 [root@ss-server ~]# echo ${sum} 16 [root@ss-server ~]# echo $((3**3)) 27 [root@ss-server ~]# echo $[3**4] 81
$ 变量符号、正则里表示"行尾"
$是变量替换的代表符号。 [root@ss-server ~]# var="wang lao hu" [root@ss-server ~]# echo $var wang lao hu [root@ss-server ~]# echo ${var} wang lao hu 另外: 在Regular Expressions里被定义为 \"行\" 的最末端。这个常用在grep、sed、awk 以及 vim(vi) 当中。 ^ 表示行首 $ 表示行尾
${} 变量的正规表达式
bash 对 ${} 定义了不少用法,如下,具体说明可参考: https://www.cnblogs.com/kevingrace/p/5996133.html
${parameter:-word} ${parameter:=word} ${parameter:?word} ${parameter:+word} ${parameterffset} ${parameterffset:length} ${!prefix*} ${#parameter} ${parameter#word} ${parameter##word} ${parameter%word} ${parameter%%word} ${parameter/pattern/string} ${parameter//pattern/string}
$* 所有引用的变量
$* 引用script的执行引用变量,引用参数的算法与一般指令相同,指令本身为0,其后为1,然后依此类推。引用变量的代表方式如下:
$0, $1, $2, $3, $4, $5, $6, $7, $8, $9, ${10}, ${11}.....
个位数的,可直接使用数字,但两位数以上,则必须使用 {} 符号来括住。 具体使用含义后面有详细说明
$* 则是代表所有引用变量的符号。使用时,得视情况加上双引号。
[root@ss-server ~]# echo "$*" "" [root@ss-server ~]# echo "$*" [root@ss-server ~]# cat test.sh #!/bin/bash USER=$1 AGE=$2 ADD=$3 HE=$4 echo "$1 is $2,come from $3,and $4" echo "$*" [root@ss-server ~]# sh test.sh 张阳 20 安徽 帅气 张阳 is 20,come from 安徽,and 帅气 张阳 20 安徽 帅气
$@ 所有引用的变量
$@ 与 $* 具有相同作用的符号,不过它们两者有一个不同点。
符号 $* 将所有的引用变量视为一个整体。但符号 $@ 则仍旧保留每个引用变量的区段观念。 [ $@ 与 $* 二者的区别在下面会详细提到]
$# 参数变量的总数量
这也是与引用变量相关的符号,它的作用是告诉你,引用变量的总数量是多少。
[root@ss-server ~]# cat a.sh #!/bin/bash USER=$1 AGE=$2 ADD=$3 HE=$4 echo "$1 is $2,come from $3,and $4" echo "$*" echo "$@" echo "$#" [root@ss-server ~]# sh a.sh 黄涛 30 杭州 黄涛 is 30,come from 杭州,and 黄涛 30 杭州 黄涛 30 杭州 3 [root@ss-server ~]# echo "$#" "0" [root@ss-server ~]# echo "$#" 0
$? 状态值 (status variable)
一般来说,Linux 系统的进程以执行系统调用exit()来结束的。这个回传值就是status值。回传给父进程,用来检查子进程的执行状态。
一般指令程序倘若执行成功,其$?回传值为 0;若执行失败,则$?回传值为 1。
[root@ss-server ~]# ls a.sh a.sh [root@ss-server ~]# echo $? 0 [root@ss-server ~]# ls aa.sh ls: cannot access aa.sh: No such file or directory [root@ss-server ~]# echo $? 2
$$ 当前shell的PID
由于进程的ID是唯一的,所以在同一个时间,不可能有重复性的 PID。有时,script会需要产生临时文件,用来存放必要的资料。而此script亦有可能在同一时间被使用者们使用。在这种情况下,固定文件名在写法上就显的不可靠。唯有产生动态文件名,才能符合需要。符号$$或许可以符合这种需求。它代表当前shell 的 PID。
[root@ss-server ~]# echo "hello world" hello world [root@ss-server ~]# echo $$ 78520 [root@ss-server ~]# echo "hello world" > aa.$$ [root@ss-server ~]# cat aa.78520 hello world [root@ss-server ~]# cat a.sh #!/bin/bash USER=$1 AGE=$2 ADD=$3 HE=$4 echo "$1 is $2,come from $3,and $4" echo "$#" echo "$*" echo "$@" echo "$$" echo "$0" [root@bz3aomsmsap1002 ~]sh a.sh 张阳 20 安徽 帅气 张阳 is 20,come from 安徽,and 帅气 4 张阳 20 安徽 帅气 张阳 20 安徽 帅气 90261 a.sh
使用它来作为文件名的一部份,可以避免在同一时间,产生相同文件名的覆盖现象。
基本上,系统会回收执行完毕的 PID,然后再次依需要分配使用。所以 script 即使临时文件是使用动态档名的写法,如果script 执行完毕后仍不加以清除,会产生其他问题。
( ) 指令群组 (command group)
用括号将一串连续指令括起来,这种用法对 shell 来说,称为指令群组。如下面的例子:
[root@ss-server ~]# (cd ~ ; pwstr=`pwd` ;echo ${pwstr}) /root
指令群组有一个特性,shell会以产生 subshell来执行这组指令。因此,在其中所定义的变数,仅作用于指令群组本身。来看个例子:
[root@ss-server ~]# cat a.sh #!/bin/bash a=wang b=zhang (a=han ; echo -e "\n $a \n") (b=xiaoru; echo -e "this is $b") echo $a echo $b [root@ss-server ~]# sh a.sh han this is xiaoru wang zhang 由上面可知:shell的指令群组所定义的变数,仅作用于指令群组本身。 来看看echo的几个操作效果 ============================================================= [root@ss-server ~]# echo "aa" aa [root@ss-server ~]# echo \"aa\" "aa" [root@ss-server ~]# echo -e "\n wang \n" wang [root@ss-server ~]# echo -e \"\n wang \n\" # 这种情况下,\n就不是换行符了,因为双引号也被转义了。 "n wang n"
除了上述的指令群组,括号也用在 array数组变数的定义上;另外也应用在其他可能需要加上escape字元才能使用的场合,如运算式。
(( ))
这组符号的作用与 let 指令相似,用在算数运算上,是 bash 的内建功能。所以,在执行效率上会比使用 let指令要好许多。
[root@ss-server ~]# cat a.sh #!/bin/bash (( a = 10 )) echo -e "inital value, a = $a\n" (( a++)) echo "after a++, a = $a" [root@ss-server ~]# sh a.sh inital value, a = 10 after a++, a = 11
请记住:
$(())、$[] 这两个效果是一样的,都是运算符号,显示运算结果。
let 也是运算符号,设置运算
[root@ss-server ~]# echo $((4*9)) 36 [root@ss-server ~]# echo $[4*9] 36 [root@ss-server ~]# let a=4*9 [root@ss-server ~]# echo $a 36 [root@ss-server ~]# let "a=4*9" [root@ss-server ~]# echo $a 36 [root@ss-server ~]# let a="3+5" [root@ss-server ~]# echo $a 8 [root@ss-server ~]# a=10 [root@ss-server ~]# let a++ #表示变量a数值加1 [root@ss-server ~]# echo $a 11
{ } 大括号
这种大括号的组合,常用在字串的组合上,来看个例子
[root@ss-server ~]# mkdir aa{1,2,3} [root@ss-server ~]# ls aa1 aa2 aa3 [root@ss-server ~]# ll -d bb1* drwxr-xr-x 2 root root 4096 Dec 5 11:37 bb1-k01 drwxr-xr-x 2 root root 4096 Dec 5 11:37 bb1-k02 drwxr-xr-x 2 root root 4096 Dec 5 11:37 bb1-k03 [root@ss-server ~]# ll -d cc1* drwxr-xr-x 2 root root 4096 Dec 5 11:37 cc1-k01 drwxr-xr-x 2 root root 4096 Dec 5 11:37 cc1-k02 drwxr-xr-x 2 root root 4096 Dec 5 11:37 cc1-k03 [root@ss-server ~]# ll -d dd1* drwxr-xr-x 2 root root 4096 Dec 5 11:37 dd1-k01 drwxr-xr-x 2 root root 4096 Dec 5 11:37 dd1-k02 drwxr-xr-x 2 root root 4096 Dec 5 11:37 dd1-k03 [root@ss-server ~]# touch {wan,han}_{1,2,3} [root@ss-server ~]# ls wan* wan_1 wan_2 wan_3 [root@ss-server ~]# ls han* han_1 han_2 han_3 [root@ss-server ~]# chmod 755 /root/wan_{1,2,3} [root@ss-server ~]# ll /root/wan_{1,2,3} -rwxr-xr-x 1 root root 0 Dec 5 11:39 /root/wan_1 -rwxr-xr-x 1 root root 0 Dec 5 11:39 /root/wan_2 -rwxr-xr-x 1 root root 0 Dec 5 11:39 /root/wan_3
这组符号在适用性上相当广泛。能加以善用的话,回报是精简与效率。像下面的例子
?表示任意单个字符!!! [root@ss-server ~]# chown app.app /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}
如果不是因为支援这种用法,我们得写几行重复几次呀!
[ ] 中括号
常出现在流程控制中,扮演括住判断式的作用。
[root@ss-server ~]# ls hahaha ls: cannot access hahaha: No such file or directory [root@ss-server ~]# echo $? 2 [root@ss-server ~]# cat a.sh #!/bin/bash ls hahaha >/dev/null 2>&1 if [ "$?" != 0 ];then echo "Executes error" exit 1 fi [root@ss-server ~]# sh a.sh Executes error
这个符号在正则表达式中担任类似 "范围" 或 "集合" 的角色
[root@ss-server ~]# touch aaa{1,2,3,4} [root@ss-server ~]# ls aaa* aaa1 aaa2 aaa3 aaa4 [root@ss-server ~]# rm -f aaa[1234] [root@ss-server ~]# ls aaa* ls: cannot access aaa*: No such file or directory 注意: rm -f aaa[1234] 表示删除aaa1、aaa2、aaa3、aaa4 相当于 rm -f aaa{1,2,3,4} 注意: 只有在删除文件的时候,[]可以起到上面类似 "范围" 或 "集合" 的角色! 在其他操作都不会起到该作用! 如下,在touch的时候,[]并没有起到范围或集合的作用! [root@ss-server ~]# touch aa[123] [root@ss-server ~]# touch aa[123]_[xyz] [root@ss-server ~]# ls aa* aa[123] aa[123]_[xyz]
[[ ]]
这组符号与先前的 [] 符号,基本上作用相同,但它允许在其中直接使用 || 与&& 逻辑等符号。||表示"或",&&表示"和" 。双中括号[[]]和单中括号[]的区别,在下面会详细提到。
[root@ss-server ~]# cat a.sh #!/bin/bash read -p "请输入一个数字: " num if [[ ${num} > 10 && ${num}< 30 ]];then echo "你输入的数字是${num}" else echo "输入的数字不符合要求" fi [root@ss-server ~]# sh a.sh 请输入一个数字: 16 你输入的数字是16 [root@ss-server ~]# sh a.sh 请输入一个数字: 56 输入的数字不符合要求 上面脚本还可以改写为下面内容,效果是一样的! [root@ss-server ~]# cat a.sh #!/bin/bash #echo -n表示不换行 echo -n "输入一个数字: " read num if [[ ${num} > 10 && ${num}< 30 ]];then echo "你输入的数字是${num}" else echo "输入的数字不符合要求" fi [root@ss-server ~]# sh a.sh 输入一个数字: 19 你输入的数字是19 [root@ss-server ~]# sh a.sh 输入一个数字: 48 输入的数字不符合要求 =============================================== 需要注意: if判断语句中如果使用[[]],可以在[[]]中直接使用&&、||符号,表示"和"、"或"。可以用于字符串对比符号,也可以用于整数对比符号。 if判断语句中如果使用[],在[]中可以使用-a、-o,表示"和"、"或",但是这个用于整数比较时只能使用"-eq、-ne、-ge、-gt、-lt、-le",不能使用>、>=、<、<=、=、!=。 [root@ss-server ~]# cat a.sh #!/bin/bash read -p "请输入一个数字: " num if [ ${num} -gt 10 -a ${num} -le 30 ];then echo "你输入的数字是${num}" else echo "输入的数字不符合要求" fi [root@ss-server ~]# sh a.sh 请输入一个数字: 12 你输入的数字是12 [root@ss-server ~]# sh a.sh 请输入一个数字: 45 输入的数字不符合要求 上面脚本中的[ ${num} -gt 10 -a ${num} -le 30 ] 不能改为: [ ${num} -ge 10 ] -a [${num} -le 30 ] 也不能改为 [ ${num} > 10 -a ${num} < 30 ] [[]]的&&、||也可以用于整数对比。 [root@ss-server ~]# cat a.sh #!/bin/bash read -p "请输入一个数字: " num if [[ ${num} -ge 10 && ${num} -le 30 ]];then echo "你输入的数字是${num}" else echo "输入的数字不符合要求" fi [root@ss-server ~]# sh a.sh 请输入一个数字: 17 你输入的数字是17 [root@ss-server ~]# sh a.sh 请输入一个数字: 67 输入的数字不符合要求
|| 逻辑符号
这个会时常看到,代表 or 逻辑的符号,表示前一个命令执行成功,则就此结束,后一个命令就不执行;前一个命令执行失败,后一个命令才会执行。如 A || B 表示A执行成功后,B就不会再执行了;A执行失败或不执行,B才能执行。
&& 逻辑符号
这个也会常看到,代表 and 逻辑的符号,表示串行,即前一个命令执行成功,后一个命令才接着执行;前一个命令执行失败,则就此结束,后一个命令也不会执行。如 A && B 表示A执行成功后,B也会跟着执行了;A执行失败或不执行,B也不会执行了。
& 后台工作
单一个& 符号,且放在完整指令列的最后端,即表示将该指令列放入后台中工作。 放在几个指令中间时,表示并行,实质就是在后台并行执行,跟指令前后顺序无关。
[root@ss-server ~]# tar -zvcf test1.tar.gz test1 > /dev/null &
\<...\> 单字边界
这组符号在规则表达式中,被定义为\"边界\"的意思。如下想要在test文件中找寻 the 这个单字时,如果我们用
[root@ss-server ~]# cat test the there this is a 123456 thee [root@ss-server ~]# grep "the" test the there thee
如上会发现,像 there、thee这类的单字,也会被当成是匹配的单字。因为 the 正巧是there、thee的一部份。如果要想必免这种情况,就得加上单字边界符号,进行精准匹配:
[root@ss-server ~]# cat test the there this is a 123456 thee [root@ss-server ~]# grep "the" test the there thee [root@ss-server ~]# grep "\<the\>" test the 另外:上面在进行grep精准匹配时,除了使用\<str\>单字边界符号,还可以使用grep -w进行精准匹配! [root@ss-server ~]# cat test the there this is a 123456 thee [root@ss-server ~]# grep -w "the" test the 可以参考:https://www.cnblogs.com/kevingrace/p/9299232.html
+ 加号
在运算式中,她用来表示 "加法"。
[root@ss-server ~]# expr 10 + 11 + 12 33 注意:expr命令中的计算符号和数字中间一定要有空格!!否则无效!并且后面的运算两边不能有引号,否则也无效! 下面都是错误的!! [root@ss-server ~]# expr 10+11+12 10+11+12 [root@ss-server ~]# expr "10 + 11 + 12" 10 + 11 + 12 另外:注意expr使用*乘法的时候,需要在*前面加上转义符号\,否则无效! [root@ss-server ~]# expr 2 * 3 expr: syntax error [root@ss-server ~]# expr 2 \* 3 6
此外在正则表达式中,用来表示"很多个"的前面字元的意思。但是注意,正则里使用+符号表示"很多个"意思时,+号前面必须加上\\符号!!
[root@ss-server ~]# cat test 123456 10aaaahuihhhhh s34eddddd kkkhuan [root@ss-server ~]# grep "10\\+a" test 10aaaahuihhhhh [root@ss-server ~]# grep "e\\+d" test s34eddddd [root@ss-server ~]# grep "\\k" test kkkhuan
- 减号
在运算式中,她用来表示 "减法"。
[root@ss-server ~]# expr 10 - 2 8
在 cd 指令中则比较特别,"cd -"表示变更工作目录到\"上一次\"工作目录。
[root@ss-server ~]# cd /usr/local/src/ [root@bz3aomsmsap1002 src]# cd [root@ss-server ~]# cd - /usr/local/src [root@bz3aomsmsap1002 src]#
% 除法后的余数
在运算式中,用来表示 "除法"后的余数。 [运算式中的乘法*,用的时候需要在前面加一个转移符 expr 5 \* 10]
[root@ss-server ~]# expr 10 % 2 0 [root@ss-server ~]# expr 10 % 3 1 [root@ss-server ~]# expr 10 % 6 4 [root@ss-server ~]# expr 6 % 9 6 [root@ss-server ~]# expr 6 % 90 6 [root@ss-server ~]# expr 5 % 6 5 %表示余数,即整除后的余数是多少。 如果小除大,则%余数统一为前面那个小的数。
此外,也被运用在关于变量的规则表达式当中的下列
${parameter%word} ${parameter%%word} 一个 % 表示最短的 word 匹配,两个表示最长的 word 匹配。 可以参考上面"参数替换"部分有详细介绍
= 等号
常在设定变数时看到的符号。
[root@ss-server ~]# vara="hello world" [root@ss-server ~]# echo "vara=${vara}" vara=hello world
或者像是 PATH 的设定,甚至应用在运算或判断式等此类用途上。
== 等号
常在条件判断式中看到,代表 "等于" 的意思。
if [ $vara == $varb ]
...下略
!= 不等于
常在条件判断式中看到,代表 "不等于" 的意思。
if [ $vara != $varb ]
...下略
^
这个符号在正则表达式中,代表行的 "开头" 位置!
输出/输入重导向
> 、>>、< 、<< 、<>、>&、>&2
文件描述符(File Descriptor),用一个数字(通常为0-9)来表示一个文件。
常用的文件描述符如下:
文件描述符 名称 常用缩写 默认值
0 标准输入 stdin 键盘
1 标准输出 stdout 屏幕
2 标准错误输出 stderr 屏幕
在简单地用<或>时,相当于使用 0< 或 1>。如下面说明:
# cmd > file
把cmd命令的输出重定向到文件file中。如果file已经存在,则清空原有文件,使用bash的noclobber选项可以防止复盖原有文件。[即>表示覆盖内容]
# cmd >> file
把cmd命令的输出重定向到文件file中,如果file已经存在,则把信息加在原有文件後面。 [即>>表示追加内容]
# cmd < file
使cmd命令从file读入
# cmd << text
从命令行读取输入,直到一个与text相同的行结束。除非使用引号把输入括起来,此模式将对输入内容进行shell变量替换。如果使用<<- ,则会忽略接下来输入行首的tab,结束行也可以是一堆tab再加上一个与text相同的内容,可以参考後面的例子。
# cmd <<< word
把word(而不是文件word)和後面的换行作为输入提供给cmd。
# cmd <> file
以读写模式把文件file重定向到输入,文件file不会被破坏。仅当应用程序利用了这一特性时,它才是有意义的。
# cmd >| file
功能同>,但即便在设置了noclobber时也会复盖file文件,注意用的是|而非一些书中说的!,目前仅在csh中仍沿用>!实现这一功能。
: > filename 把文件\"filename\"截断为0长度.# 如果文件不存在, 那么就创建一个0长度的文件(与'touch'的效果相同).
# cmd >&n 把输出送到文件描述符n
# cmd m>&n 把输出 到文件符m的信息重定向到文件描述符n
# cmd >&- 关闭标准输出
# cmd <&n 输入来自文件描述符n
# cmd m<&n m来自文件描述各个n
# cmd <&- 关闭标准输入
# cmd <&n- 移动输入文件描述符n而非复制它。(需要解释)
# cmd >&n- 移动输出文件描述符 n而非复制它。(需要解释)
注意: >&实际上复制了文件描述符,这使得cmd > file 2>&1与cmd 2>&1 >file的效果不一样。
关于EOF用法:https://www.cnblogs.com/kevingrace/p/6257490.html
通常在执行一个命令时,如果不想打印命令执行的结果(包括正确或错误的结果信息),则通常使用"command >/dev/null 2>&1"
Shell中几种特殊的参数变量的引用
$1、$2、$3……${10}、${11}、${12}…… :表示脚本传入的的各个参数,注意当需表示两位数以后的参数时数字要用花括号括起。
$@ 列出所有的参数,各参数用空格隔开
$* 列出所有的参数,各参数用环境变量的第一个字符隔开
$* 和 $@ 的区别
1)$* 将所有的引用变量视为一个整体。但$@则仍旧保留每个引用变量的区段观念。
2)当不加引号时,$*和$@二者都是返回传入的参数,但是当加了引号后,$*把参数作为一个字符串整体(单字符串)返回,$@把每个参数作为一个字符串返回!
1) 示例1 [root@ss-server ~]# cat a.sh #!/bin/bash for i in $* do echo $i done echo "++++++ \$*和\$@对比(不加双引号) ++++++" for j in $@ do echo $j done [root@ss-server ~]# sh a.sh aa bb cc aa bb cc ++++++ $*和$@对比(不加双引号) ++++++ aa bb cc 2) 示例2 [root@ss-server ~]# cat a.sh #!/bin/bash for i in "$*" do echo $i done echo "++++++ \$*和\$@对比(加双引号) ++++++" for j in "$@" do echo $j done [root@ss-server ~]# sh a.sh aa bb cc aa bb cc ++++++ $*和$@对比(加双引号) ++++++ aa bb cc 3)示例3,在一个shell函数里分别定义 加双引号和不加双引号 传参时,$@和$*的区别 [root@ss-server ~]# cat a.sh #! /bin/bash function test() { echo "未加引号,二者相同" echo $* echo $@ echo "加入引号后对比" echo "----"\$*----"" for N in "$*" do echo $N done echo "----"\$@----"" for N in "$@" do echo $N done } test 11 22 33 [root@ss-server ~]# sh a.sh 未加引号,二者相同 11 22 33 11 22 33 加入引号后对比 ----$*---- 11 22 33 ----$@---- 11 22 33 ==================================================================================== 通过上面对比,可以发现: 不加引号时,$*和$@二者都是返回传入的参数; 加了引号后,$*把参数作为一个字符串整体(单字符串)返回,$@把每个参数作为一个字符串返回!
命令列表
and列表 statement1 && statement2 && ..... 表示只有在前面所有的命令都执行成功的情况下才执行后一条命令;即前面成功,后面继续执行;前面失败,后面也不执行!
or列表 statement1 || statement2 || ….. 表示允许执行一系列命令直到有一条命令成功为止,其后所有命令将不再被执行;即前面成功,后面不执行;前面失败,后面执行!!
[root@ss-server ~]# cat a.sh #!/bin/bash touch file_one >/dev/null 2>&1 rm -f file_two >/dev/null 2>&1 if [ -f file_one ] && echo "hello" && [ -f file_two ] && echo " there";then echo "in if" else echo "in else" fi exit 0 [root@ss-server ~]# sh a.sh hello in else
if逻辑判断语句中常用到的参数 以及 注意细节 (如[[]]和[]的区别)
[ -a file ] 如果 file 存在则为真。 [ -e file ] 如果 file 存在则为真。 [ -f file ] 如果 file 存在且是一个普通文件则为真。 [ -d file ] 如果 file 存在且是一个目录则为真。 [ -b file ] 如果 file 存在且是一个块特殊文件则为真。(即设备文件,如/dev/sda1、/dev/sda2) [ -h file ] 如果 file 存在且是一个符号文件则为真。(符号文件即是软链接文件) [ -L file ] 如果 file 存在且是一个符号文件则为真。(符号文件即是软链接文件) [ -g file ] 如果 file 存在且已经设置了SGID则为真。 [ -u file ] 如果 file 存在且设置了SUID则为真。 [ -k file ] 如果 file 存在且已经设置了粘制位则为真。(即设置了t权限的目录,粘制位仅对目录有效) [ -r file ] 如果 file 存在且是可读的则为真。 [ -w file ] 如果 file 存在且是可写的则为真。 [ -x file ] 如果 file 存在且是可执行的则为真。 [ -s file ] 如果 file 存在且大小不为0则为真。 [ -O file ] 如果 file 存在且属有效用户ID则为真。 [ -G file ] 如果 file 存在且属有效用户组则为真。 [ file1 -nt file2 ] 如果 file1 比 file2 要老(即先创建), 或者 file1 存在且 file2不存在则为真。 [ file1 -ot file2 ] 如果 file1 比 file2 要老(即先创建), 或者 file2 存在且 file1 不存在则为真。 [ -z str ] 如果str字符串的长度为零则为真。 (即空串为真) [ -n str ] or [ str ] 如果str字符串的长度为非零则为真。 (即非空串为真) [ str1 == str2 ] 如果2个字符串相同则为真。 [ str1 != str2 ] 如果字符串不相等则为真。 二、简单总结 =========================================================================== 1)字符串判断 str1 = str2 当两个串有相同内容、长度时为真 str1 != str2 当串str1和str2不等时为真 -n str1 当串的长度大于0时为真(串非空) -z str1 当串的长度为0时为真(空串) str1 当串str1为非空时为真。等于"-n star1" 2)数字的判断 int1 -eq int2 两数相等为真 int1 -ne int2 两数不等为真 int1 -gt int2 int1大于int2为真 int1 -ge int2 int1大于等于int2为真 int1 -lt int2 int1小于int2为真 int1 -le int2 int1小于等于int2为真 3)文件的判断 -a file 文件存在为真 -z file 文件存在为真 -r file 用户可读为真 -w file 用户可写为真 -x file 用户可执行为真 -f file 文件为普通文件为真 -d file 文件为目录为真 -s file 文件大小非0时为真 -h file 文件为符号文件为真 -L file 文件为符号文件为真 -g file 文件为SGID权限文件为真 -u file 文件为SUID权限文件为真 -k file 文件为T权限文件为真 4)复杂逻辑判断 -a 与 -o 或 ! 非 三、注意细节 =========================================================================== 1)在if的中括号中,判断变量的值,加不加双引号的问题? -z 判断变量的值,是否为空: 变量的值,为空,返回0,为true 变量的值,非空,返回1,为false -n 判断变量的值,是否为空: 变量的值,为空,返回1,为false 变量的值,非空,返回0,为true str="abc" [ -z "$str" ] 单中括号,变量必须要加双引号! [[ -z $str ]] 双中括号,变量不用加双引号 [ -n "$str" ] 单中括号,变量必须要加双引号! [[ -n $str ]] 双中括号,变量不用加双引号 2)多个条件判断,[] 和 [[]] 的区别???????????????????? && 并且,相当于and || 或,相当于or -a 并且,相当于and -o 或者,相当于or -------------------------------------------- 2.1)双中括号[[]]的条件判断 [[ ]] 双中括号的条件判断用"&&" 和 "||" || 满足一个条件满足就成立;或者的关系 [[ $a -lt 3 || $a -gt 6 ]] [[ $a -lt 3 ]] || [[ $a -gt 6 ]] # 写在外面也可以 && 必须同时满足两个条件同时;并且的关系。 [[ $a -gt 3 && $a -lt 10 ]] [[ $a -gt 3 ]] && [[$a -lt 10 ]] # 写在外面也可以 这里需要注意的问题的是: [[]]双中括号的判断语句中,只能使用&&和||,可以在[[]]内部使用,也可以在[[]]外面使用! [[]]双中括号的判断语句中不能使用-a和-o参数!!!!!! 如果使用下面写法就是错误的!!!!!! [[ $a -lt 3 -o $a -gt 6 ]] [[ $a -lt 3 ]] -o [[ $a -gt 6 ]] [[ $a -gt 3 -a $a -lt 10 ]] [[ $a -gt 3 ]] -a [[$a -lt 10 ]] -------------------------------------------- 2.2)单中括号[]的条件判断 [ ] 单中括号的条件判断可以使用-a和-o的参数,但是必须在单[ ]中括号内判断条件!!不能在单中括号外面!! [ $a -lt 10 -o $a -gt 20 ] 这个"或者"条件成立 [ $a -lt 10 ] -o [ $a -gt 20 ] 这个"或者"不成立,因为必须在中括号内判断!!!! 如果想在[]中括号外判断两个条件,必须用&& 和 || 比较! [ $a -lt 10 ] || [ $a -gt 20 ] 这个"或者"条件成立 [ $a -lt 10 ] && [ $a -gt 20 ] 这个"并且"条件成立 同样需要注意:|| 和 && 不能在单中括号[]内使用,只能在单中括号[]外面使用!!! 3) 当判断某个变量的值是否满足正则表达式的时候,必须使用[[ ]] 双中括号!!!! 示例: [root@ss-server ~]# str=13611082178 [root@ss-server ~]# [[ ${str} =~ [0-9]{11} ]] [root@ss-server ~]# echo $? 0 如果使用单中括号,会直接报错: [root@ss-server ~]# str=13611082178 [root@ss-server ~]# [ ${str} =~ [0-9]{11} ] -bash: [: =~: binary operator expected
shell脚本获取第10个参数 在Shell脚本中,可以用$n的方式获取第n个参数 [root@ansible-server ~]# cat a.sh #!/bin/bash echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} [root@ansible-server ~]# sh a.sh a b c d 1 2 3 4 8 ab a b c d 1 2 3 4 8 ab 取第10个参数, 要用${10}, 不能使用$10(这个表示第1个参数加上0)。因为个位数的参数,可以直接使用数字。但两位以上数字的参数,必须使用{}符号!!!! #!/bin/bash echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 [root@ansible-server ~]# sh a.sh a b c d 1 2 3 4 8 ab a b c d 1 2 3 4 8 a0 即上面脚本中$10 取的值为$1+0 再看几个例子 [root@ansible-server ~]# cat a.sh #!/bin/bash #echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 echo $3 $12 [root@ansible-server ~]# sh a.sh a b c d 1 2 3 4 8 ab c a2 [root@ansible-server ~]# cat a.sh #!/bin/bash #echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 echo $3 ${12} [root@ansible-server ~]# sh a.sh a b c d 1 2 3 4 8 ab bo kevin c kevin
$# 是传递给脚本的参数个数;
$0 是脚本本身的名字;
$1 是传递给该shell脚本的第一个参数;
$2 是传递给该shell脚本的第二个参数;
$@ 是传递给脚本的所有参数的列表(是多个字符串,每个参数为1个字符串);
$* 是传递给脚本的所有参数的列表(以一个单字符串显示所有参数),与位置变量不同,参数可超过9个;
$$ 是运行脚本的当前进程ID号;
$? 是显示执行上一条Shell命令的返回值,0表示没有错误,其他表示有错误。
如下,用一个简单的脚本来说明上面这些变量的含义 [root@kevin ~]# vim /root/path.sh #!/bin/sh echo "the number of parameters passed to the script: $#" echo "the name of the script itself: $0" echo "the first parameter passed to the shell script: $1" echo "the second parameter passed to the shell script: $2" echo "the list of all the parameters passed to the script(some string): $@" echo "the list of all the parameters passed to the script(one string): $*" echo "the current process ID number of the script which is running: $$" echo "the return value of the last shell command performed: $?" [root@kevin ~]# chmod 755 /root/path.sh [root@kevin ~]# ll /root/path.sh -rwxr-xr-x. 1 root root 512 Jun 25 11:21 /root/path.sh [root@kevin ~]# sh /root/path.sh 10 20 30 the number of parameters passed to the script: 3 the name of the script itself: /root/path.sh the first parameter passed to the shell script: 10 the second parameter passed to the shell script: 20 the list of all the parameters passed to the script(some string): 10 20 30 the list of all the parameters passed to the script(one string): 10 20 30 the current process ID number of the script which is running: 372 the return value of the last shell command performed: 0
Shell脚本常用命令 -exit 和 if
1、exit exit 0 退出shell,成功 exit 1 退出shell,失败 exit 2 退出shell,用法不当 需要注意: 如果shell脚本中调用的子脚本的exit,那么会退出子脚本 如果是source一个子脚本,里面的exit会导致外面的脚本也退出 ============================================================== 2、if 1) if [-z "$name"] 判断name是否为空字符串,如果空,则为真,执行if的内容 等同于 if ["$name" = ""] 等同于[! "$name"] 2) if的几个参数 -z 字符串是否为空,空为真 -n 指定字符串是否不空,不空为真 -a 某东西不存在,则为真。不限定为字符串 -f 普通文件是否存在 -d 目录是否存在 -e 某东西是否存在,不限定为文件
Shell脚本中判断参数是否为空,如果为空就停止后续操作
注意下面的方法 if [ str1 = str2 ] 当两个串有相同内容、长度时为真 if [ str1 != str2 ] 当串str1和str2不等时为真 if [ -n str1 ] 当串的长度大于0时为真(串非空) 。 注意: 这个等同于if [ ! -n str1 ] ,前提是里面的str1不加上"",如果加上""就等同于if [ -z str1 ]了! if [ -z str1 ] 当串的长度为0时为真(空串) 。 注意:这个等同于 if [ ! -n "str1" ],前提是str1必须要加上""双引号!! ================================================================== [root@bz3aomsmsap1002 mnt]# cat test.sh #!/bin/bash AN="" BN="sadf" if [ -z ${AN} ];then echo "没有变量AN,无法执行后续操作,请确认输入了AN参数" exit 1 fi echo "结果为:${AN} is a good ${BN}" [root@bz3aomsmsap1002 mnt]# sh test.sh 没有变量AN,无法执行后续操作,请确认输入了AN参数 ----------------------------------------- [root@bz3aomsmsap1002 mnt]# cat test.sh #!/bin/bash AN="ha" BN="sadf" if [ -z ${AN} ];then echo "没有变量AN,无法执行后续操作,请确认输入了AN参数" exit 1 fi echo "结果为:${AN} is a good ${BN}" [root@bz3aomsmsap1002 mnt]# sh test.sh 结果为:ha is a good sadf ================================================================== 如果要想使用-n代替-z,则做法如下: 必须注意: 下面的if判断语句中的-n后面的变量必须要加上双引号""!否则就失效! 因为如果不加""的话,就等同于了效于if [ -n ] [root@bz3aomsmsap1002 mnt]# cat test.sh #!/bin/bash AN="" BN="sadf" if [ ! -n "${AN}" ];then echo "没有变量AN,无法执行后续操作,请确认输入了AN参数" exit 1 fi echo "结果为:${AN} is a good ${BN}" [root@bz3aomsmsap1002 mnt]# sh test.sh 没有变量AN,无法执行后续操作,请确认输入了AN参数 ----------------------------------------- [root@bz3aomsmsap1002 mnt]# cat test.sh #!/bin/bash AN="ru" BN="sadf" if [ ! -n "${AN}" ];then echo "没有变量AN,无法执行后续操作,请确认输入了AN参数" exit 1 fi echo "结果为:${AN} is a good ${BN}" [root@bz3aomsmsap1002 mnt]# sh test.sh 结果为:ru is a good sadf ----------------------------------------- 如果不加双引号,则if [ ! -n ] 就等同于了 -f [ -n ] [root@bz3aomsmsap1002 mnt]# cat test.sh #!/bin/bash AN="" BN="sadf" if [ ! -n ${AN} ];then echo "没有变量AN,无法执行后续操作,请确认输入了AN参数" exit 1 fi echo "结果为:${AN} is a good ${BN}" [root@bz3aomsmsap1002 mnt]# sh test.sh 结果为: is a good sadf ----------------------------------------- [root@bz3aomsmsap1002 mnt]# cat test.sh #!/bin/bash AN="ru" BN="sadf" if [ ! -n ${AN} ];then echo "没有变量AN,无法执行后续操作,请确认输入了AN参数" exit 1 fi echo "结果为:${AN} is a good ${BN}" [root@bz3aomsmsap1002 mnt]# sh test.sh 结果为:ru is a good sadf
$(( ))、$( )、${ }的区别
=================================================================== 一、$( ) 与 ` ` (反引号) 在bash shell中,$( ) 与 ` `(反引号) 都是用来做命令替换用(command substitution)的。 [root@bobo tmp]# echo `hostname` kevin-testserver [root@bobo tmp]# echo $(hostname) kevin-testserver 比如查看上一星期天的日期 [root@bobo tmp]# echo the last sunday is $(date -d "last sunday" +%Y-%m-%d)[/code] the last sunday is 2019-10-27[/code] =================================================================== 二、${ } 用来作变量替换。 一般情况下,$var 与 ${var} 并没有什么不一样。但是用${ }会比较精确的界定变量名称的范围。 例如下面的例子,原本是打算先将$A的结果替换出来,然后再补一个B字母于其后。 如果使用$AB打印结果就为空,但是使用${A}B打印就不一样了。 [root@bobo tmp]# A=B [root@bobo tmp]# echo $AB [root@bobo tmp]# echo ${A}B BB [root@bobo tmp]# 在bash中。${ }功能是十分强大的,不仅仅是用来界定变量名称, -------------------------------------- 1)${}可以灵活地用来截图变量中的字符串 具体可以参考:https://www.cnblogs.com/kevingrace/p/8868262.html 例如:var="http://www.kevin.com/shibo/anhuigrace" 我们可以用 ${ } 分别替换获得不同的值: ${var#*/}:拿掉第一条/及其左边的字符串:/www.kevin.com/shibo/anhuigrace ${var##*/}:拿掉最后一条/及其左边的字符串:anhuigrace ${var#*.}:拿掉第一个.及其左边的字符串:kevin.com/shibo/anhuigrace ${var##*.}:拿掉最后一个.及其左边的字符串:com/shibo/anhuigrace ${var%/*}:拿掉最后一条/及其右边的字符串:http://www.kevin.com/shibo ${var%%/*}:拿掉第一条/及其右边的字符串:http: ${var%.*}:拿掉最后一个.及其右边的字符串:http://www.kevin ${var%%.*}:拿掉第一个.及其右边的字符串:http://www 记忆的方法为: # 是去掉左边(在键盘上 # 在 $ 之左边) % 是去掉右边(在键盘上 % 在 $ 之右边) 单一符号是最小匹配﹔ 两个符号是最大匹配。 -------------------------------------- 2)${}可以对变量值里的字符串作替换 ${file/dir/path}:将第一个 dir提换为path: ${file//dir/path}:将全部dir提换为path: 示例: [root@bobo tmp]# cat test.sh #!/bin/bash var="/data/web/kevin/www/web/ui/web/list" echo "${var}" echo "${var/web/shi}" echo "${var//web/shi}" [root@bobo tmp]# sh test.sh /data/web/kevin/www/web/ui/web/list /data/shi/kevin/www/web/ui/web/list /data/shi/kevin/www/shi/ui/shi/list -------------------------------------- 3) 利用 ${ } 还可针对不同的变量状态赋值(没设定、空值、非空值) ${var-kevin.txt}:假如$var没有设定,则使用kevin.txt作传回值。(空值及非空值时不作处理) ${var:-kevin.txt}:假如$var没有设定或为空值,则使用kevin.txt作传回值。(非空值时不作处理) ${var+kevin.txt}:假如$var设为空值或非空值,均使用kevin.txt作传回值。(没设定时不作处理) ${var:+kevin.txt}:若$var为非空值,则使用kevin.txt作传回值。(没设定及空值时不作处理) ${var=kevin.txt}:若$var没设定,则使用kevin.txt作传回值,同时将$var赋值为kevin.txt。(空值及非空值时不作处理) ${var:=kevin.txt}:若$var没设定或为空值,则使用kevin.txt作传回值,同时将$var赋值为kevin.txt。(非空值时不作处理) ${var?kevin.txt}:若$var没设定,则将kevin.txt输出至STDERR。(空值及非空值时不作处理) ${var:?kevin.txt}:若$var没设定或为空值,则将kevin.txt输出至STDERR。(非空值时不作处理) 示例: [root@bobo tmp]# cat test.sh #!/bin/bash #var="/data/web/kevin/www/web/ui/web/list" echo "${var}" echo "${var-my.txt}" echo "${var:-my.txt}" echo "${var+my.txt}" echo "${var:+my.txt}" echo "${var=my.txt}" echo "${var:=my.txt}" echo "${var?my.txt}" echo "${var:?my.txt}" [root@bobo tmp]# sh test.sh my.txt my.txt my.txt my.txt my.txt my.txt 修改下脚本 [root@bobo tmp]# cat test.sh #!/bin/bash var="/data/web/kevin/www/web/ui/web/list" echo "${var}" echo "${var-my.txt}" echo "${var:-my.txt}" echo "${var+my.txt}" echo "${var:+my.txt}" echo "${var=my.txt}" echo "${var:=my.txt}" echo "${var?my.txt}" echo "${var:?my.txt}" [root@bobo tmp]# sh test.sh /data/web/kevin/www/web/ui/web/list /data/web/kevin/www/web/ui/web/list /data/web/kevin/www/web/ui/web/list my.txt my.txt /data/web/kevin/www/web/ui/web/list /data/web/kevin/www/web/ui/web/list /data/web/kevin/www/web/ui/web/list /data/web/kevin/www/web/ui/web/list 需要注意的是: 以上理解一定要分清楚unset 与 null 及 non-null 这三种赋值状态。一般而言: : 与 null 有关; 若不带 : 的话, 则 null 不受影响,; 若带 : 的话,则连 null 也受影响. -------------------------------------- 4)${#var} 可计算出变量值的长度 [root@bobo tmp]# cat test.sh #!/bin/bash var="/data/web/kevin/www/web/ui/web/list" echo "${#var}" [root@bobo tmp]# sh test.sh 35 这里就引申出shell中的数组的概念了,数组的使用可以参考:https://www.cnblogs.com/kevingrace/p/5761975.html 这里简单说明下: 一般而言,var="haha hehe heihei houhou" 这样的变量只是将${var}替换为一个单一的字符串, [root@bobo tmp]# var="haha hehe heihei houhou" You have mail in /var/spool/mail/root [root@bobo tmp]# echo ${var} haha hehe heihei houhou 如果改为 var=(haha hehe heihei houhou) ,则是将${var}定义为组数。 [root@bobo tmp]# var=(haha hehe heihei houhou) bash 的组数替换方法可参考如下方法: ${var[@]} 或 ${var[*]} 可得到 haha hehe heihei houhou (全部组数) ${var[0]} 可得到 haha (第一个组数),${var[1]} 则为第二个组数… ${#var[@]} 或 ${#var[*]} 可得到 4 (全部组数数量) ${#var[0]} 可得到4(即第一个组数(haha)的长度),${#var[3]} 可得到6(第四个组数(houhou)的长度) var[3]=xyz 则是将第四个组数重新定义为xyz … [root@bobo tmp]# echo ${var[@]} haha hehe heihei houhou [root@bobo tmp]# echo ${var[*]} haha hehe heihei houhou [root@bobo tmp]# echo ${var[0]} haha [root@bobo tmp]# echo ${var[1]} hehe [root@bobo tmp]# echo ${#var[@]} 4 [root@bobo tmp]# echo ${#var[*]} 4 [root@bobo tmp]# echo ${#var[0]} 4 [root@bobo tmp]# echo ${#var[3]} 6 [root@bobo tmp]# var[3]=xyz [root@bobo tmp]# echo ${var[@]} haha hehe heihei xyz =================================================================== 三、 $(( )) 的用途: 1)$(( ))是用来作整数运算的。 + - * / :分别为 "加、减、乘、除"。 % :余数运算 & | ^ !:分别为 "AND、OR、XOR、NOT" 运算。 [root@bobo tmp]# a=5; b=7; c=2 [root@bobo tmp]# echo $(( a+b*c )) 19 [root@bobo tmp]# echo $(( (a+b)/c )) 6 [root@bobo tmp]# echo $(( (a*b)%c)) 1 在 $(( )) 中的变量名称,可于其前面加 $ 符号来替换,也可以不用,如: [root@bobo tmp]# echo $(( $a + $b * $c)) 19 [root@bobo tmp]# echo $(( ($a * $b) % $c)) 1
Shell 脚本中诸如查看目录大小并排序等技巧
===================================================================== 查看目录下的文件大小并排序 1. 查看/data目录下空间大小排在前10位的文件 # du -sh /data/* | sort -nr | head -10 查看目录下所有文件的大小并按照大小排序 # du -sh * | sort -rh 2. 查看/data目录下空间大小排在前10位的目录(单位为G),并且只是在/data当前目录下查看,不轮询(用到参数"-maxdepth 1") # find /data/* -maxdepth 1 -type d -exec /usr/bin/du -sh {} \;|grep '[0-9]G'|sort -rh|head -5 [bxapp@bz6aomdepap1001 ~]$ find /data/ftp/ONLINE/* -maxdepth 1 -type d -exec /usr/bin/du -sh {} \;|grep '[0-9]G'|sort -rh|head -5 64G /data/ftp/ONLINE/CCS 13G /data/ftp/ONLINE/MPB 11G /data/ftp/ONLINE/ICS 9.5G /data/ftp/ONLINE/mysql 9.0G /data/ftp/ONLINE/EOB ===================================================================== Shell中求字符串中单词的个数的几种方法 方法一: [root@VM_16_9_centos tmp]# echo 'wang shi kevin ruo bao' | wc -w 5 方法二: [root@VM_16_9_centos tmp]# echo 'wang shi kevin ruo bao' | awk '{print NF}' 5 方法三: [root@VM_16_9_centos tmp]# s='wang shi kevin ruo bao' [root@VM_16_9_centos tmp]# set ${s} [root@VM_16_9_centos tmp]# echo $# 5 方法四: [root@VM_16_9_centos tmp]# s='wang shi kevin ruo bao' [root@VM_16_9_centos tmp]# a=($s) [root@VM_16_9_centos tmp]# echo ${#a[@]} 5 方法五: [root@VM_16_9_centos tmp]# s='wang shi kevin ruo bao' [root@VM_16_9_centos tmp]# echo $s | tr ' ' '\n' | wc -l 5 ===================================================================== linux 中wc 用法小结 wc命令用于统计给定文件中的字节数、字数、行数。 如果没有给出文件名,则从标准输入读取。 wc同时也给出所有指定文件的总统计数。字是由空格字符区分开的最大字符串。 wc命令各选项含义如下: - c 统计字节数 - l 统计行数 - w 统计字数 1. 统计行数: # wc -l file 2. 如果需要将stdin作为输入,使用下列命令: #cat file | wc -l 3. 统计单词数: # wc -w file # cat file | wc -w 4. 统计字符数: # wc -c file # cat file | wc -c 可以按照下面的方法统计文本中的字符数: -n用于避免echo添加额外的换行符。 [root@VM_16_9_centos tmp]# echo "CCS"|wc -c 4 [root@VM_16_9_centos tmp]# echo -n "CCS"|wc -c 3 4 5. 当不使用任何选项执行wc时: # wc file 1435 15763 112200 它会分别打印出文件的行数、单词数和字符数。 6. 使用-L选项打印出文件中最长一行的长度: # wc file -L 205 ===================================================================== shell求两个数相除后的百分比 [root@VM_16_9_centos tmp]# [root@VM_16_9_centos tmp]# cat test.sh #!/bin/bash NUM1=78 NUM2=345 Percent_1=$(printf "%d%%" $((${NUM1}*100/${NUM2}))) #或者 #保留1位小数,四舍五入 Percent_2=`awk 'BEGIN{printf "%.1f%%\n",('${NUM1}'/'${NUM2}')*100}'` #保留3位小数,四舍五入 Percent_3=`awk 'BEGIN{printf "%.3f%%\n",('${NUM1}'/'${NUM2}')*100}'` echo $Percent_1 echo $Percent_2 echo $Percent_3 [root@VM_16_9_centos tmp]# sh test.sh 22% 22.6% 22.609%