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

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/pattern/replacement}:查找var变量存储的字符中第一次由pattern匹配到的内容,并替换为replacement;
    ${var//pattern/replacement}:查找var变量存储的字符中所有能够由pattern匹配到的内容,并替换为replacement;
    例子:
=> 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 编程中的应用

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容