Linux shell 中一些符号$() ` `,${},$[]

2019-08-21  本文已影响0人  danria

Shell中经常遇到一些符号容易混淆,今天一起总结学习下加深理解。

1. $()``

$()`` (反引号) 都是用来做命令替换用的。
我们直接看例子:

=> echo 5加4等于:$(expr 5 + 4)
5加4等于:9
=> echo 5加4等于:`expr 5 + 4`
5加4等于:9

在操作上,这两者都是达到相同的效果,但是建议使用$(),理由如下:
在多层次的复合替换中,`` 必须要转义处理(反斜线),而$()比较直观。如下例子(只是为了说明多层次命令,不用介意具体运算):

=> echo 5加4加1等于:$(expr $(expr 5 + 4 ) + 1)
5加4加1等于:10
=> echo 5加4加1等于:`expr \`expr 5 + 4\` + 1`
5加4加1等于:10
2. ${} :变量替换

${}用于变量替换。一般情况下,$var${var} 结果差不多。但是用 ${}会精确的界定变量名称的范围。例子:

=> file="test";echo $file_txt
#空值,因为没有定义file_txt
=> file="test";echo ${file}_txt
test_txt

${}的一些其他功能:

1)${}信息提取

主要有以下四种, 此部分内容参考学习(Linux shell 之 提取文件名和目录名的一些方法):
我们以var=/home/test/dir1/dir2/V3_L01_99_2.fq.gz为例说明
A. ${var##*.}:该命令的作用是去掉变量var从左边算起的最后一个'.'字符及其左边的内容,返回从左边算起的最后一个'.'(不含该字符)的右边的内容。结果如下:

=> var=/home/test/dir1/dir2/V3_L01_99_2.fq.gz
=> echo ${var##*.}
gz

因此使用该命令,可以提取出我们需要的文件后缀。

B、${var#*.}: 该命令的作用是去掉变量var从左边算起的第一个'.'字符及其左边的内容,返回从左边算起第一个'.'(不含该字符)的右边部分的内容。例子结果如下:

=> var=/home/test/dir1/dir2/V3_L01_99_2.fq.gz
=> echo ${var#*.}
fq.gz

使用该命令,可以提取出文件的多个后缀。

C、${var%/*}: 该命令的使用是去掉变量var从右边算起的第一个'/'字符及其右边的内容,返回从右边算起的第一个'/'(不含该字符)的左边的内容。例子结果如下:

=> var=/home/test/dir1/dir2/V3_L01_99_2.fq.gz
=> echo ${var%/*}
/home/test/dir1/dir2

从结果可看出,使用该命令,可以提取出需要的文件所在的目录。

D、${var%%.*}: 该命令的使用是去掉变量var从右边算起的最后一个'.'字符及其右边的内容,返回从右边算起的最后一个'.'(不含该字符)的左边的内容。使用例子及结果如下:

=> var=/home/test/dir1/dir2/V3_L01_99_2.fq.gz
=> echo ${var%%.*}
/home/test/dir1/dir2/V3_L01_99_2

使用该命令,可以提取出需要的文件除去多个后缀后的路径与文件名。
从这也可发现一些规律,即:
#:表示从左边算起第一个
##:表示从左边算起最后一个
%:表示从右边算起第一个
%%:表示从右边算起最后一个

当然上述操作的作用并不只是为了提取文件名或后缀,只是为了说明${}在信息提取上的应用;shell中文件名或后缀的提取可直接使用basename和dirname,还是以上述为例:
=> var=/home/test/dir1/dir2/V3_L01_99_2.fq.gz
=> echo $(basename $var)
V3_L01_99_2.fq.gz
=> echo $(basename $var .fq.gz)
V3_L01_99_2
=> echo $(dirname $var)
/home/test/dir1/dir2
2)${} substring 按字符位置、长度截取

格式:${var:offset:length},取得字符串的子字符串
直接看例子:

var=/home/test/dir1/dir2/V3_L01_99_2.fq.gz
echo ${var:0:5} #从头开始,提取最左边的 5 个字节,结果:/home
echo ${var:5}   #从提取第 5 个字节右边到结尾的字符,结果:/test/dir1/dir2/V3_L01_99_2.fq.gz
echo ${var:5:5} #提取第 5 个字节右边的连续 5 个字节,结果;/test
echo ${#var}    #计算出字符串的长度,结果:38
echo ${var: -5} #注意区分,中间有空格,提取最后五个字符,结果:fq.gz
echo ${var:-5}  #结果:/home/test/dir1/dir2/V3_L01_99_2.fq.gz,为啥值等于$var,下面部分有解释
echo ${var:(-5)} #注意上面三者的区分,结果:fq.gz

3)${} 查找替换和删除

此部分参考学习:bash字符串处理

=> var=/home/test/dir1/dir2/V3_L01_99_2.fq.gz;echo ${var/dir/path}
/home/test/path1/dir2/V3_L01_99_2.fq.gz
=> var=/home/test/dir1/dir2/V3_L01_99_2.fq.gz;echo ${var//dir/path}
/home/test/path1/path2/V3_L01_99_2.fq.gz

${var/pattern}:查找var变量存储的字符中第一次由pattern匹配到的内容,并删除;
${var//pattern}:查找var变量存储的字符中所有能够由pattern匹配到的内容,并删除;
${var/#pattern}:查找var变量存储的字符中最开始处能够由pattern匹配到的内容,并删除;
${var/%pattern}:查找var变量存储的字符中最后位置能够由pattern匹配到的内容,并删除;
例子如下:

=> var=home/test/dir1/home2/dir2/home;echo ${var/home}
/test/dir1/home2/dir2/home
=> var=home/test/dir1/home2/dir2/home;echo ${var//home}
/test/dir1/2/dir2/
=> var=home/test/dir1/home2/dir2/home;echo ${var/#home}
/test/dir1/home2/dir2/home
=> var=home/test/dir1/home2/dir2/home;echo ${var/%home}
home/test/dir1/home2/dir2/
4)${} 大小写替换

^替换为大写,^^统统替换为大写
,替换为小写,,,统统替换为小写

var="home/test/dir1/dir2/V3_L01_99_2.fq.gz"
echo ${var^} # Home/test/dir1/dir2/V3_L01_99_2.fq.gz
echo ${var^^} # HOME/TEST/DIR1/DIR2/V3_L01_99_2.FQ.GZ
echo ${var,} # home/test/dir1/dir2/V3_L01_99_2.fq.gz
echo ${var,,} # home/test/dir1/dir2/v3_l01_99_2.fq.gz
5)利用 ${} 还可针对不同的变量状态赋值(初始化、空值、非空值)

本部分参考学习https://blog.csdn.net/x1269778817/article/details/46535729

变量设定
这也是上部分${var:-5} 结果为啥还是等于$var的原因。
6) ${} 数组与关联数组

shell中的数组与关联数组
声明数组: declare -a array
声明关联数组: declare -A MAP

declare -a ARY     #声明数组
declare -A MAP    #声明关联数组
MAP=([a]=1 [b]=2 [cde]=3 [f]=F)     #关联数组MAP
ARY=(a b cde f)                              #数组ARY

echo ${ARY[2]}                               #数组ARY,从0开始,因此是第三个元素,cde
echo ${#ARY[2]}                             #数组ARY,第三个元素的长度, 3
echo ${ARY[@]}                             #数组所有元素, a b cde f
echo ${ARY[*]}                                #数组所有元素, a b cde f
echo ${#ARY[@]}                            #数组大小, 4
echo ${ARY[@]:0:2}                        #数组从头开始前两个元素,a b
echo ${ARY[@]: -2:2}                      #注意-2前面有空格,原因上面讲过,从最后一个元素-1开始向左数2个元素,cde f
echo ${MAP[@]}                              #关联数组所有值,1 3 2 F
echo ${#MAP[@]}                           #关联数组大小,4
echo ${MAP[cde]}                           #关联数组cde的值,3
echo ${!MAP[@]}                             #返回索引,a cde b f

3. $[]$(())

进行数学运算。支持+ - * / %:分别为 “加、减、乘、除、求余",如下:

a=10;b=8;c=5;
echo $a + $b          #输出:10 + 8
echo $(( a + b*c))    #输出:50
echo $(((a*b)/c))      #输出:16

#在 $(( )) 中的变量名称,其前面可以加 $ 符号,也可以不用,如:

echo $(( $a + $b * $c)) # 输出也是 50

$[]$(()) 的过去形式,现在已经不建议使用

4. []

即为test命令的另一种形式。

但要注意:

1).必须在左括号的右侧和右括号的左侧各加一个空格,否则会报错。

2).test命令使用标准的数学比较符号来表示字符串的比较,而用文本符号来表示数值的比较。

3).字符比较的大于符号或小于符号必须要转义,否则会被理解成重定向。

4). []中的逻辑与和逻辑或使用-a 和-o 表示
例子:

num=10
str1=abc
#字符串
if [ $str1 = "abc" ];then
  echo "this is $str1"
fi
# 输出:this is abc
# 数字
if [ $num -gt 1 -a $num -lt 20 ];then
  echo "this is $num"
fi
# 输出:this is 10
if [ $num -gt 1 ] && [ $num -lt 20 ];then
  echo "this is $num"
fi
# 输出:this is 10

[]条件判断的一些总结,此部分参考来源全网最全的 bash 速查表 ;

statement1 && statement2  # and 操作符
statement1 || statement2  # or 操作符

exp1 -a exp2              # exp1 和 exp2 同时为真时返回真(POSIX XSI扩展)
exp1 -o exp2              # exp1 和 exp2 有一个为真就返回真(POSIX XSI扩展)
( expression )            # 如果 expression 为真时返回真,输入注意括号前反斜杆
! expression              # 如果 expression 为假那返回真

str1 = str2               # 判断字符串相等,如 [ "$x" = "$y" ] && echo yes
str1 != str2              # 判断字符串不等,如 [ "$x" != "$y" ] && echo yes
str1 < str2               # 字符串小于,如 [ "$x" \< "$y" ] && echo yes
str2 > str2               # 字符串大于,注意 < 或 > 是字面量,输入时要加反斜杆
-n str1                   # 判断字符串不为空(长度大于零)
-z str1                   # 判断字符串为空(长度等于零)

-a file                   # 判断文件存在,如 [ -a /tmp/abc ] && echo "exists"
-d file                   # 判断文件存在,且该文件是一个目录
-e file                   # 判断文件存在,和 -a 等价
-f file                   # 判断文件存在,且该文件是一个普通文件(非目录等)
-r file                   # 判断文件存在,且可读
-s file                   # 判断文件存在,且尺寸大于0
-w file                   # 判断文件存在,且可写
-x file                   # 判断文件存在,且执行
-N file                   # 文件上次修改过后还没有读取过
-O file                   # 文件存在且属于当前用户
-G file                   # 文件存在且匹配你的用户组
file1 -nt file2           # 文件1 比 文件2 新
file1 -ot file2           # 文件1 比 文件2 旧

num1 -eq num2             # 数字判断:num1 == num2
num1 -ne num2             # 数字判断:num1 != num2
num1 -lt num2             # 数字判断:num1 < num2
num1 -le num2             # 数字判断:num1 <= num2
num1 -gt num2             # 数字判断:num1 > num2
num1 -ge num2             # 数字判断:num1 >= num2
5. (())[[]]

(())[[]]分别是针对数学比较表达式字符串表达式的加强版。
可参考:Bash test and comparison functions

  1. [[ ]] 结构比[ ]结构更加通用
  2. [[ ]]支持字符串的模式匹配,使用=~操作符时甚至支持shell的正则表达式。
    继续上面例子:
num=10
str1=abc

if [[ $num -gt 1 && $num -lt 20 ]];then
  echo "this is $num"
fi
# 输出:this is 10,注意写成[ $num -gt 1 && $num -lt 20 ]会出错;
if [[ $str1 =~ ab ]];then
  echo "this is $str1"
fi
# 输出:this is abc

(( ))相比(),不需要再将表达式里面的大小于符号转义,除了可以使用标准的数学运算符外,还增加了自增自减等符号;如

for ((i = 0; i < 10; i++)); do echo $i; done
# 输出0-9的数

其他功能,如{n..m} 代表n-m之间的数字,如{0..4}$(seq 0 4)表示相同意思。/{,s}bin/表示/bin/和/sbin/,ab{c,d,e}表示abc、abd、abe,如实现文件的快速备份:cp run.sh{,.bak}。
当然随时可查看bash 速查表

有参考Shell 参数扩展及各类括号在 Shell 编程中的应用

上一篇下一篇

猜你喜欢

热点阅读