#《快乐的 Linux 命令行》

#字符展开

1
echo *
1
2
$ echo *
anaconda-ks.cfg certbot-auto ls-output.txt uniq-test

shellecho命令被执行前把*展开成了另外的东西。

当回车键被按下时,shell在命令被执行前在命令行上自动展开任何符合条件的字符,所以echo命令的实际参数并不是*,而是它展开后的结果

#路径名展开

通配符所依赖的工作机制叫做路径名展开

1
2
$ echo D*
Desktop Documents Downloads
1
2
$ echo *s
Applications Documents Downloads Movies Pictures sensors
1
2
$ echo [[:upper:]]*
Applications Desktop Documents Downloads Library Movies Music Pictures Postman Public
1
2
$ echo /usr/*/share
/usr/local/share

以圆点字符开头的文件名是隐藏文件,路径名展开也尊重这种行为,echo *不会显示隐藏文件。

~当它用在一个单词的开头时,它会展开成指定用户的家目录名,如果没有指定用户名,则展开成当前用户的家目录:

1
2
$ echo ~
/Users/onns

如果有用户foo这个帐号,那么:

1
2
$ echo ~foo
/home/foo

#算术表达式展开

shell在展开中执行算数表达式,这允许我们把shell提示当作计算器来使用:

1
$((expression))
1
2
$ echo $((2*3))
6

算术表达式只支持整数。

然而我好像用了不是整数的数,也算出来结果了,可能和Linux版本有关系:

1
2
$ echo $((5.2423/2))
2.6211500000000001

支持的运算符:+ - * / % **

因为只支持整数,所以除法的结果也是整数

1
2
$ echo $((5/2))
2

在算术表达式中空格并不重要,并且表达式可以嵌套。

1
2
$ echo $(($((5**2)) * 3))
75

#花括号展开

可以从一个包含花括号的模式中创建多个文本字符串。

1
2
$ echo Front-{A,B,C}-Back
Front-A-Back Front-B-Back Front-C-Back

花括号展开模式可能包含一个开头部分叫做报头,一个结尾部分叫做附言

花括号表达式本身可能包含一个由逗号分开的字符串列表,或者一个整数区间,或者单个的字符的区间

这种模式不能嵌入空白字符。

1
2
$ echo Number_{1..5}
Number_1 Number_2 Number_3 Number_4 Number_5
1
2
$ echo {Z..A}
Z Y X W V U T S R Q P O N M L K J I H G F E D C B A

花括号展开可以嵌套:

1
2
$ echo a{A{1,2},B{3,4}}b
aA1b aA2b aB3b aB4b

还有一些参数变量展开:

1
2
echo $USER
onns

但在参数展开中,如果你拼写错了一个变量名,展开仍然会进行,只是展开的结果是一个空字符串:

1
echo $SUER

#命令替换

命令替换允许我们把一个命令的输出作为一个展开模式来使用:

1
2
$ echo $(ls)
Applications Desktop Documents Downloads Library Movies Music Pictures Postman Public go node sensors
1
2
$ ls -l $(which cp)
-rwxr-xr-x 1 root wheel 42272 May 28 07:37 /bin/cp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ file $(ls /usr/bin/* | grep zip)
/usr/bin/bunzip2: Mach-O 64-bit executable x86_64
/usr/bin/bzip2: Mach-O 64-bit executable x86_64
/usr/bin/bzip2recover: Mach-O 64-bit executable x86_64
/usr/bin/funzip: Mach-O 64-bit executable x86_64
/usr/bin/gunzip: Mach-O 64-bit executable x86_64
/usr/bin/gzip: Mach-O 64-bit executable x86_64
/usr/bin/unzip: Mach-O 64-bit executable x86_64
/usr/bin/unzipsfx: Mach-O 64-bit executable x86_64
/usr/bin/zip: Mach-O 64-bit executable x86_64
/usr/bin/zipcloak: Mach-O 64-bit executable x86_64
/usr/bin/zipdetails: Perl script text executable
/usr/bin/zipdetails5.18: Perl script text executable
/usr/bin/zipdetails5.28: Perl script text executable
/usr/bin/zipgrep: POSIX shell script text executable, ASCII text
/usr/bin/zipinfo: Mach-O 64-bit executable x86_64
/usr/bin/zipnote: Mach-O 64-bit executable x86_64
/usr/bin/zipsplit: Mach-O 64-bit executable x86_64

在旧版shell程序中,有另一种语法也支持命令替换,使用倒引号来代替美元符号和括号:

1
2
$ ls -l `which cp`
-rwxr-xr-x 1 root wheel 42272 May 28 07:37 /bin/cp

#引用

双引号包裹的字符串,单词分割路径名展开波浪线展开花括号展开会失效,参数展开算术展开命令替换仍然执行。

1
2
3
4
5
6
7
8
$ echo "$USER $((2+2)) $(cal)"
onns 4 November 2020
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30

例外的是$ \ `

在默认情况下,单词分割机制会在单词中寻找空格制表符,和换行符,并把它们看作单词之间的界定符。这意味着无引用的空格,制表符和换行符都不是文本的一部分,它们只作为分隔符使用。

虽然命令替换还有效果,但是有时候可能会有用:

1
2
3
4
5
6
7
8
9
10
$ echo $(cal)
November 2020 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
$ echo "$(cal)"
November 2020
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30

如果需要禁止所有的展开,我们要使用单引号

1
2
$ echo '$USER $((2+2)) $(cal)'
$USER $((2+2)) $(cal)

也可以用单个的转义字符反斜杠\

注意在单引号中,反斜杠失去它的特殊含义,它被看作普通字符。