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%
posted @ 2016-09-22 14:59  散尽浮华  阅读(11739)  评论(0编辑  收藏  举报