8. 扩展符
示例:
$ echo *
这里输出当前目录下的所有文件,而不是输出 * 号。因为 shell 会在命令执行结果输出前自动解析命令行中的指定字符。
路径名扩展符
示例:
$ echo D*
$ echo *s
$ echo [[:upper:]]*
$ echo /usr/*/share
波浪号~扩展
~
在单词开头表示指定用户的家目录,如果未指定用户名,则表示当前登录用户的家目录,如:echo ~foo
输出 /home/foo(如果 foo 用户存在)。
算术扩展
示例:
$ echo $((2 + 2))
格式:
$ $((expression))
只支持整数,空格在表达式中无意义,表达式可嵌套。例如:
$ echo $(($((5**2)) * 3))
可以简写为:
$ echo $(((5**2) * 3))
$ echo Five divided by two equals $((5/2))
结果为 2。
$ echo with $((5%2)) left over.
结果为 1。
中括号扩展符
示例:
$ echo Front-{A,B,C}-Back
使用逗号分隔字符串或整数或字符列表。且不能包含空格。连续整数的示例:
$ echo Number_{1..5}
连续字母示例:
$ echo {Z..A}
嵌套示例:
$ echo a{A{1,2},B{3,4}}b
输出结果:
aA1b aA2b aB3b aB4b
其最常见的用处是用于列出需要创建的文件和目录列表。例如,如果你要整理你的照片,批量按年月创建目录:
$ mkdir Photos
$ cd Photos
$ mkdir {2007..2009}-0{1..9} {2007..2009}-{10..12}
$ ls
结果如下:
2007-01 2007-07 2008-01 2008-07 2009-01 2009-07
2007-02 2007-08 2008-02 2008-08 2009-02 2009-08
2007-03 2007-09 2008-03 2008-09 2009-03 2009-09
2007-04 2007-10 2008-04 2008-10 2009-04 2009-10
2007-05 2007-11 2008-05 2008-11 2009-05 2009-11
2007-06 2007-12 2008-06 2008-12 2009-06 2009-12
变量扩展符
USER
参数包含你的用户名:
$ echo $USER
查看环境变量列表:
$ printenv | less
如果 $
符后面的单词不在上面的列表中,那么会输出空字符串,否则会解析变量,输出变量的值。
命令替换
可以使用 $(cmd)
将 cmd 命令的结果作为字符串返回。
示例:
$ echo $(ls)
$ ls -l $(which cp)
输出示例:
-rwxr-xr-x 1 root wheel 29008 3 28 2018 /bin/cp
当命令结果有多行时,会对每行依次执行:
$ file $(ls /usr/bin/* | grep bin/zip)
在旧版本的 shell 中使用反引号代替 $ 符表达式:
$ ls -l `which cp`
引号
示例:
$ echo this is a test
以上多个空格会压缩为一个空格输出。
$ echo The total is $100.00
以上 $1
会被当作不存在的变量,而输出空字符串输出,最终输出:The total is 00.00
双引号
双引号中的文本中,所有特殊字符都会失去其特殊意义,而被当作普通字符。除了 $
、\
、和反引号是例外。这就意味着分词、路径扩展符、波浪线扩展符和中括号扩展符在双引号中是无效的,但是,变量扩展符、算术扩展符和命令替换仍是有用的。另外,双引号可以用于带空格的文件名。例如,要查看名为 two words.txt 的文件:
$ ls -l two words.txt
结果示例:
ls: cannot access two: No such file or directory
ls: cannot access words.txt: No such file or directory
这时,你可以使用双引号来查看该文件并修改文件名:
ls -l "two words.txt"
mv "two words.txt" two_words.txt
仍有效的示例:
$ echo "$USER $((2+2)) $(cal)"
默认情况下,分词会查找空格、TAB 和新行符作为单词分隔符。这就意味着上述字符不会当作文本的一部分。只会当作分隔符。它们将单词分隔为不同的参数,如果使用双引号的话,例如:
$ echo "this is a test"
那么分词功能就不起作用了,空格就不会被当作分隔符,而是参数的一部分了。 对比以下两个命令的结果:
$ echo $(cal)
$ echo "$(cal)"
第一个命令将 $(cal)
的结果当成了 38 个参数依次输出。第二个命令中 $(cal)
的结果被当作是一个参数,包含空格符和换行符。
单引号
如果你想禁用所有扩展符,使用单引号。对比以下命令的输出:
$ echo text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER
$ echo "text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER"
$ echo 'text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER'
从上面例子中可以看出:
- 不带引号时,所有扩展符可用
- 带双引号时,
$
符可用,包括命令替换、变量扩展、算术。而{}
和~
不可用。也就是说,除$
符相关的扩展符外,其他字符都被当作普通字符串。 - 带单引号时,所有扩展符皆不可用
转义字符
转义字符使用 \
反斜杠,主要用于抑制扩展符,例如:
$ echo "The balance for user $USER is: \$5.00"
当文件名中包含 $
、!
、&
和空格等 shell 中的特殊字符时,也可以使用转义字符,例如:
$ mv bad\&filename good_filename
如果要对 \
转义,使用 \\
。注意在单引号中,\
会失去其转义功能,而被当作普通字符。
更多反斜杠技巧
如果你看 man
程序中的文档,你会看到很多 -
和 --
的命令参数:
$ ls -r
$ ls --reverse
为什么有两种类型?一般 -
表示缩写参数,--
表示完整参数。使用 -
很朦胧,而 --
更易理解。
如果全部用 --
形式,那么一个命令就会很长,这时可以使用反斜杠来转义换行符:
$ ls -l \
--reverse \
--human-readable \
--full-time
注意 \
后面必须是换行符,不能有空格,否则会转义空格,而不是换行符。转义符也可以用于在文本中插入特殊字符。它们称为 反斜杠转义字符。以下是常见的:
转义符 | 名称 | 使用场景 |
---|---|---|
\n |
新行 | 在文本中添加空行 |
\t |
tab | 在文本中添加水平制表符 |
\a |
告警 | 让终端响铃 |
\\ |
反斜杠 | 插入一个反斜杠 |
\f |
换页 | 发送到打印机弹出页面 |
将 echo
命令与 -e
选项一起使用:
$ echo -e "Inserting several blank lines\n\n\n"
$ echo -e "Words\tseparated\tby\thorizontal\ttabs."
$ echo -e "\aMy computer went \"beep\"."
$ echo -e "DEL C:\\WIN2K\\LEGACY_OS.EXE"