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
-
[[ ]]
结构比[ ]
结构更加通用 -
[[ ]]
支持字符串的模式匹配,使用=~操作符时甚至支持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 速查表