IT序号网

shell中${}和()的使用知识解答

wyy 2021年05月25日 程序员 165 0

1. 截断功能

"${1^^}_DOC_CHANGE_PID"  #变量转换为大写

"${1,,}_DOC_CHANGE_PID"  #变量转换为小写

${!DOC_CHANGE_PID} #取变量的值

${file#*/}:       拿掉第一条/及其左边的字符串:dir1/dir2/dir3/my.file.txt 
${file##*/}:    拿掉最后一条/及其左边的字符串:my.file.txt 
${file#*.}:       拿掉第一个.及其左边的字符串:file.txt 
${file##*.}:    拿掉最后一个.及其左边的字符串:txt 
${file%/*}:     拿掉最后条/及其右边的字符串:/dir1/dir2/dir3 
${file%%/*}: 拿掉第一条/及其右边的字符串:(空值) 
${file%.*}:    拿掉最后一个.及其右边的字符串:/dir1/dir2/dir3/my.file 
${file%%.*}: 拿掉第一个.及其右边的字符串:/dir1/dir2/dir3/my 
记忆的方法为: 
[list]#是去掉左边, ##最后一个 
      %是去掉右边, %%第一个

2. 字符串提取

单一符号是最小匹配﹔两个符号是最大匹配。 
${file:0:5}:提取最左边的 5 个字节:/dir1 
${file:5:5}:提取第 5 个字节右边的连续 5 个字节:/dir2

3. 字符串替换

${file/dir/path}:将第一个 dir 提换为 path:/path1/dir2/dir3/my.file.txt 
${file//dir/path}:将全部 dir 提换为 path:/path1/path2/path3/my.file.txt

4. 针对不同的变量状态赋值(没设定、空值、非空值):

${file-my.file.txt}: 若$file没有设定,则使用my.file.txt作返回值。(空值及非空值时不作处理) 
${file:-my.file.txt}:若$file没有设定或为空值,则使用my.file.txt作返回值。(非空值时不作处理) 
${file+my.file.txt}: 若$file设为空值或非空值,均使用my.file.txt作返回值。(没设定时不作处理) 
${file:+my.file.txt}:若$file为非空值,则使用my.file.txt作返回值。(没设定及空值时不作处理) 
${file=my.file.txt}: 若$file没设定,则使用my.file.txt作返回值,同时将$file 赋值为 my.file.txt。(空值及非空值时不作处理) 
${file:=my.file.txt}:若$file没设定或为空值,则使用my.file.txt作返回值,同时将 $file 赋值为 my.file.txt。(非空值时不作处理) 
${file?my.file.txt}: 若$file没设定,则将my.file.txt输出至 STDERR。(空值及非空值时不作处理) 
${file:?my.file.txt}:若$file没设定或为空值,则将my.file.txt输出至STDERR。(非空值时不作处理) 
注意:  
":+"的情况是不包含空值的. 
":-", ":="等只要有号就是包含空值(null).

5. 变量的长度

${#file}

6. 数组运算

A=(a b c def) 
${A[@]} 或 ${A[*]} 可得到 a b c def (全部组数) 
${A[0]} 可得到 a (第一个组数),${A[1]} 则为第二个组数... 
${#A[@]} 或 ${#A[*]} 可得到 4 (全部组数数量) 
${#A[0]} 可得到 1 (即第一个组数(a)的长度),${#A[3]} 可得到 3 (第四个组数(def)的长度)

7.例子

介绍下Shell中的${}、##和%%使用范例,本文给出了不同情况下得到的结果。 
假设定义了一个变量为: 
代码如下: 
file=/dir1/dir2/dir3/my.file.txt 
可以用${ }分别替换得到不同的值: 
${file#*/}:删掉第一个 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt 
${file##*/}:删掉最后一个 /  及其左边的字符串:my.file.txt 
${file#*.}:删掉第一个 .  及其左边的字符串:file.txt 
${file##*.}:删掉最后一个 .  及其左边的字符串:txt 
${file%/*}:删掉最后一个  /  及其右边的字符串:/dir1/dir2/dir3 
${file%%/*}:删掉第一个 /  及其右边的字符串:(空值) 
${file%.*}:删掉最后一个  .  及其右边的字符串:/dir1/dir2/dir3/my.file 
${file%%.*}:删掉第一个  .   及其右边的字符串:/dir1/dir2/dir3/my 
记忆的方法为: 
# 是 去掉左边(键盘上#在 $ 的左边) 
%是去掉右边(键盘上% 在$ 的右边) 
单一符号是最小匹配;两个符号是最大匹配 
${file:0:5}:提取最左边的 5 个字节:/dir1 
${file:5:5}:提取第 5 个字节右边的连续5个字节:/dir2 
也可以对变量值里的字符串作替换: 
${file/dir/path}:将第一个dir 替换为path:/path1/dir2/dir3/my.file.txt 
${file//dir/path}:将全部dir 替换为 path:/path1/path2/path3/my.file.txt

shell中的(),{}几种语法用法

 

查看脚本语法是否有错误:
bash -n modify_suffix.sh
跟踪执行
sh -x modify_suffix.sh aaa

1.${var}  
2.$(cmd)  
3.()和{}  
4.${var:-string},${var:+string},${var:=string},${var:?string}  
5.$((exp))  
6.$(var%pattern),$(var%%pattern),$(var#pattern),$(var##pattern)

1.Shell中变量的原形:${var}

 但当你要显示变量值加随意的字符(我这里用_AA)时,就会出错

这时应该用变量的原形:${var},即是加一个大括号来限定变量名称的范围

[root@bogon sh]# aa='ajax' 
[root@bogon sh]# echo $aa 
ajax 
[root@bogon sh]# echo $aa_AA 
 
[root@bogon sh]# echo ${aa}_AA 
ajax_AA

批量修改一个目录里文件名

[root@bogon ~]# cat modify_suffix.sh 
#!/bin/bash 
dst_path=$1 
for file in `ls $dst_path` 
do 
        if [ -d $1/$file ] 
                 then echo `$0 $1/$file` 
        elif [ -f $1/$file ] 
                then    mv $1/$file $1/${file}._mod 
        else 
            echo $1/${file} is unknow file type 
        fi 
 
done; 
./modify_suffix.sh  ./f 
将 ./f 下的所有文件文件名添加了.mod
[root@bogon ~]# file="modify_suffix.sh.tar.gz" 
[root@bogon ~]# echo "${file%%.*}" 
modify_suffix 
[root@bogon ~]# echo "${file%.*}" 
modify_suffix.sh.tar 
[root@bogon ~]# echo "${file#*.}" 
sh.tar.gz 
[root@bogon ~]# echo "${file##*.}" 
gz

2.$(cmd)

[root@bogon t]# ls 
1.txt  2.txt 
[root@bogon t]# echo $(ls) 
1.txt 2.txt
echo $(ls) 执行过程 
shell扫描一遍命令行,发现了$(cmd)结构,便将$(cmd)中的cmd执行一次,得到其标准输出, 
再将此输出放到原来命令 echo $(ls)中的 $(ls)位置,即替换了$(ls),再执行echo命令 
如下: 
echo $(ls)被替换成了echo 1.txt 2.txt 
这里要注意的是$(cmd)中的命令的错误输出是不会被替换的,替换的只是标准输出
[root@bogon t]# var=$(cat 3.txt) 
cat: 3.txt: 没有那个文件或目录 
[root@bogon t]# echo $var 
 
$var显然是空的

3、一串的命令执行()和{}
()和{}都是对一串的命令进行执行,但有所区别:
相同点:
()和{}都是把一串的命令放在括号里面,并且命令之间用;号隔开
不同点
()只是对一串命令重新开一个子shell进行执行,{}对一串命令在当前shell执行
()最后一个命令可以不用分号,{}最后一个命令要用分号
()里的第一个命令和左边括号不必有空格,{}的第一个命令和左括号之间必须要有一个空格
()和{}中括号里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里的所有命令

[root@bogon t]# var=test 
[root@bogon t]# echo $var 
test 
[root@bogon t]# (var=notest;echo $var) 
notest 
[root@bogon t]# echo $var 
test 
[root@bogon t]# { var=notest;echo $var;} 
notest 
[root@bogon t]# echo $var 
notest 
[root@bogon t]#

在{}中 第一个命令和{之间必须有空格,结束必须有;
{}中的修改了$var的值 说明在当前shell执行

[root@bogon t]# { var1=test1;var2=test2;echo $var1>a;echo $var2;} 
test2 
[root@bogon t]# cat a 
test1 
[root@bogon t]# { var1=test1;var2=test2;echo $var1;echo $var2;}>a 
[root@bogon t]# cat a 
test1 
test2 
脚本实例 
( 
    echo "1" 
    echo "2" 
) | awk '{print NR,$0}'

4.几种特殊的替换结构:

${var:-string},${var:+string},${var:=string},${var:?string}


(1)

${var:-string} 和 ${var:=string}

若变量var为空或者未定义,则用在命令行中用string来替换${var:-string}
否则变量var不为空时,则用变量var的值来替换${var:-string}

[root@bogon ~]# echo $a 
 
[root@bogon ~]# echo ${a:-bcc} 
bcc 
[root@bogon ~]# echo $a 
 
[root@bogon ~]# a=ajax 
[root@bogon ~]# echo ${a:-bcc} 
ajax 
[root@bogon ~]# unset a 
[root@bogon ~]# echo $a 
 
[root@bogon ~]# echo ${a:=bbc} 
bbc 
[root@bogon ~]# echo $a 
bbc

发现

${var:-string}和${var:=string}

比较 后者发现$var为空时,把string赋值给了var
后者是一种赋值默认值的常见做法

(2) ${var:+string}
规则和上面的完全相反
即只有当var不是空的时候才替换成string,若var为空时则不替换或者说是替换成变量var的值,即空值

[root@bogon ~]# a=ajax 
[root@bogon ~]# echo $a 
ajax 
[root@bogon ~]# echo ${a:+bbc} 
bbc 
[root@bogon ~]# echo $a 
ajax 
[root@bogon ~]# unset a 
[root@bogon ~]# echo $a 
 
[root@bogon ~]# echo ${a:+bbc} 
 
[root@bogon ~]# 

(3). ${var:?string}
替换规则:若变量var不为空,则用变量var的值来替换${var:?string}
若变量var为空,则把string输出到标准错误中,并从脚本中退出。
可利用此特性来检查是否设置了变量的值

[root@bogon ~]# echo $a 
 
[root@bogon ~]# echo ${a:?bbc} 
-bash: a: bbc 
[root@bogon ~]# a=ajax 
[root@bogon ~]# echo ${a:?bbc} 
ajax 
[root@bogon ~]# a=ajax 
[root@bogon ~]# echo ${a:-`date`} 
ajax 
[root@bogon ~]# unset a 
[root@bogon ~]# echo ${a:-`date`} 
2017年 02月 21日 星期二 10:13:46 CST 
[root@bogon ~]# echo ${a:-$(date)} 
2017年 02月 21日 星期二 10:13:59 CST 
[root@bogon ~]# b=bbc 
[root@bogon ~]# echo ${a:-$b} 
bbc

5.$((exp)) POSIX标准的扩展计算
这种计算是符合C语言的运算符,也就是说只要符合C的运算符都可用在$((exp)),包括三目运算符
注意:这种扩展计算是整数型的计算,不支持浮点型和字符串等
若是逻辑判断,表达式exp为真则为1,假则为0

[root@bogon ~]# echo $(3+2) 
-bash: 3+2: 未找到命令 
 
[root@bogon ~]# echo $((3+2)) 
5 
[root@bogon ~]# echo $((3.5+2)) 
-bash: 3.5+2: 语法错误: 无效的算术运算符 (错误符号是 ".5+2") 
[root@bogon ~]# echo $((3>2)) 
1 
[root@bogon ~]# echo $((3>2?'a':'b')) 
-bash: 3>2?'a':'b': 语法错误: 期待操作数 (错误符号是 "'a':'b'") 
[root@bogon ~]# echo $((3>2?a:b)) 
0 
[root@bogon ~]# echo $((a=3+2)) 
5 
[root@bogon ~]# echo $((a++)) 
5 
[root@bogon ~]# echo $a 
6

6.四种模式匹配替换结构:

${var%pattern} 
${var%%pattern} 
${var#pattern} 
${var##pattern} 
 
${var%pattern},${var%%pattern} 从右边开始匹配 
${var#pattern},${var##pattern} 从左边开始匹配 
${var%pattern} ,${var#pattern} 表示最短匹配,匹配到就停止,非贪婪 
${var%%pattern},${var##pattern} 是最长匹配

只有在pattern中使用了通配符才能有最长最短的匹配,否则没有最 长最短匹配之分
结构中的pattern支持通配符
* 表示零个或多个任意字符
?表示零个或一个任意字符
[...]表示匹配中括号里面的字符
[!...]表示不匹配中括号里面的字符

[root@bogon ~]# f=a.tar.gz 
[root@bogon ~]# echo ${f##*.} 
gz 
[root@bogon ~]# echo ${f%%.*} 
a 
[root@bogon ~]# var=abcdccbbdaa 
[root@bogon ~]# echo ${var%%d*} 
abc 
[root@bogon ~]# echo ${var%d*} 
abcdccbb 
[root@bogon ~]# echo ${var#*d} 
ccbbdaa 
[root@bogon ~]# echo ${var##*d} 
aa 
#发现输出的内容是var去掉pattern的那部分字符串的值


发布评论
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

shell根据csv生成sql知识解答
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。