假设我们定义了一个变量为: file=/dir1/dir2/dir3/my.file.txt 1.1 bash 下的 split 取“数组”的首、尾: ${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/myTips: 记忆的方法为: # 是去掉左边(在键盘上 # 在 $ 之左边) % 是去掉右边(在键盘上 % 在 $ 之右边) 单一符号是最小匹配﹔两个符号是最大匹配(类似贪婪匹配) 1.2 bash 下的 substring 按字符位置、长度截取 ${file:0:5}:提取最左边的 5 个字节:/dir1 ${file:5:5}:提取第 5 个字节右边的连续 5 个字节:/dir2 ${#file}:计算出字符串的长度,/dir1/dir2/dir3/my.file.txt 字符串长度 27 ${file: -4}:提取最后四个字符串(注意不同于echo ${file:-4}),类似用法(提取前四个字符) ${file:0:4} 1.3 bash 下的 replace 与 replaceAll 我们也可以对变量值里的字符串作替换: ${file/dir/path}:将第一个 dir 提换为 path:/path1/dir2/dir3/my.file.txt ${file//dir/path}:将全部 dir 提换为 path:/path1/path2/path3/my.file.txt 1.4 bash 下的变量空值检测与初始化 利用 ${ } 还可针对不同的变量状态赋值(没设定、空值、非空值): ${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。 (非空值时不作处理)Tips: 以上的理解在于, 你一定要分清楚 unset 与 null 及 non-null 这三种赋值状态. 一般而言, : 与 null 有关, 若不带 : 的话, null 不受影响, 若带 : 则连 null 也受影响。 而 - 和 = 的区别在于是否把传回值赋给引用变量,例如: ${parameter:-word} word is only substituted. ${parameter:=word} word is substituted and assigned to parameter. root@localhost ~ $ echo "$var" root@localhost ~ $ echo "${var:-hello}" hello root@localhost ~ $ echo "$var" root@localhost ~ $ echo "${var:=hello}" hello root@localhost ~ $ echo "$var" hello 2、各类括号在 shell/bash 编程中的应用 上面应该见识到了 shell 中大括号的强大功能,其实 shell 下有很多种括号,不像其它高级语言括号只起到语法和意义的作用,而 shell 下的每种括号除了语法、语义的作用之外,还对 shell 编程起到了功能上的扩展。 2.1 () 在子shell中运行 (a=1);echo $a,结果是空,因为a=1不是在当前shell中运行的(a=1);(echo $a)也是空的。 小技巧:(cd $path, do something) 可以让不切换当前目录而在其它目录干点别的事儿~ () 还有个功能是数组的赋值:比如a=(1 3 5),那么${a[0]}=1;${a[1]}=3;${a[2]}=5,需要注意的是,下标是从0开始的。 2.2 (()) 表达式计算 a=1;((a++));echo $a,这时a就是2了。 2.3 <() 和 >() 进程代入,可以把命令的执行结果当成文件一样读入 比如comm前一般需要sort,那就可以这样comm <(sort 1.lst) <(sort 2.lst) 或者是paste <(cut -t2 file1) <(cut -t1 file1),和管道差不多,但是支持多个输入。 2.4 $() $(cmd) 执行cmd的结果, 比如cmd是echo ls,那么就是执行ls,比如file $(which bash),which bash的结果是/bin/bash, 所以file $(which bash)等于file /bin/bash。如果你$(ls),而且你的当前目录下只有a b两个文件, 那么就是执行a b,然后系统会提示,命令没找到。$() 基本和 `` 等价。 2.5 $(()) 表达式扩展, 和(())很相似,但是这个是有点不同,$(())不能直接$((b++)),例如:b=1;echo $((++b)) 这时b等于2,显示的也是2,b=1; echo $((b++))这时b等于2,显示的是1. 2.6 [] 和 [[]],[] 就是 test,[]和[[]]都是条件表达式,不过[[]]有比[]高的容错性, 如果a为空,那么[ $a -eq 0 ]会报错,但是[[ $a -eq 0 ]]不会,所以一般都会使用[[]]或者是 [ "$a" -eq 0 ],[[]]支持的功能也比 [] 多,比如[[ aaa =~ a{3} ]],[] 还有一种用途, 如果你的当前目录下有a1-a9九个文件,你可以用a[1-9]来替代这九个文件。 有点需要注意,你不能用a[1-20]来代替a1- a20,必须要a[1-9] a1[0-9] a20。 但是需要注意的是 [[]] 数字进制转换的坑~ 2.7 $[] 是 $(()) 的过去形式,现在已经不建议使用。 2.8 {n..m} {1..30} 就是1-30,或者是/{,s}bin/表示/bin/和/sbin/,ab{c,d,e}表示abc、abd、abe, 小技巧:文件备份:cp a.sh{,.bak} 而 { cmd1; cmd2; } 的作用是定义一个命令组,一般用在单行的条件表达式中: [[ 1 -eq 2 ]] && echo True || { echo False; echo "Program will exit!"; } 其实 shell 函数的语法也是它的变体: a(){ i=$1; echo $((i++)); echo $((++i)); } && a 1 2.9 ${} 变量的Parameter Expansion, 用法很多,最基本的 ${var}1,防止变量扩展冲突,具体可以查看man bash。 转载请保留固定链接: https://linuxeye.com/program/2109.html |