第五章:引用
引用意味着保护在引号中的字符串. 引用在保护被引起字符串中的特殊字符被shell或shell脚本解释或扩展. (如果一个字符能被特殊解释为不同于它字面上表示的意思,那么这个字符是“特殊”的,比如说通配符 -- *.)
bash$ ls -l [Vv]*
-rw-rw-r-- 1 bozo bozo 324 Apr 2 15:05 VIEWDATA.BAT
-rw-rw-r-- 1 bozo bozo 507 May 4 14:25 vartrace.sh
-rw-rw-r-- 1 bozo bozo 539 Apr 14 17:11 viewdata.sh
bash$ ls -l '[Vv]*'
ls: [Vv]*: No such file or directory
在日常的演讲和写作中,我们使用双引号("")引用一个短语,使短语被分开以示特别。在Bash脚本中,当我们引用一个字符串,也会把它分隔开以表示它原来字面上的意思。
某些程序和软件包可以重新解释或扩展引号里的特殊字符。引号一个很重要的作用是保护命令行上的一个参数不被shell解释,而把此参数传递给要执行的程序来处理它。
bash$ grep '[Ff]irst' *.txt
file1.txt:This is the first line of file1.txt.
file2.txt:This is the First line of file2.txt.
注意在Bash shell下如果没有用引号的命令grep [Ff]irst *.txt会怎么样。[1]
引号也能改掉echo's不换行的“习惯”。
bash$ echo $(ls -l)
total 8 -rw-rw-r-- 1 bozo bozo 130 Aug 21 12:57 t222.sh -rw-rw-r-- 1 bozo bozo 78 Aug 21 12:57 t71.sh
bash$ echo "$(ls -l)"
total 8
-rw-rw-r-- 1 bozo bozo 130 Aug 21 12:57 t222.sh
-rw-rw-r-- 1 bozo bozo 78 Aug 21 12:57 t71.sh
5.1. 引用变量
当要引用一个变量的值时,一般推荐使用双引号。使用双引号除了变量名[2]前缀($)、后引符(`)和转义符(\)外,会使shell不再解释引号中其它所有的特殊字符。[3] 用双引号时
用双引号还能使句子不被分割开. [4] 一个参数用双引号引起来能使它被看做一个单元,这样即使参数里面包含有空白字符也不会被shell分割开了。
1 variable1="a variable containing five words"
2 COMMAND This is $variable1 # 用下面7个参数执行COMMAND命令:
3 # "This" "is" "a" "variable" "containing" "five" "words"
4
5 COMMAND "This is $variable1" # 用下面1个参数执行COMMAND命令:
6 # "This is a variable containing five words"
7
8
9 variable2="" # 空字符串。
10
11 COMMAND $variable2 $variable2 $variable2 # 没有带参数执行COMMAND 命令
12 COMMAND "$variable2" "$variable2" "$variable2" # 用三个含空字符串的参数执行COMMAND命令
13 COMMAND "$variable2 $variable2 $variable2" # 用一个包含两个空白符的参数执行COMMAND命令
在echo语句中,只有句子分割和保存空白符的时候,才需要把参数用双引号引起来。
例子 5-1. 引号引起奇怪的变量
1 #!/bin/bash
2 # weirdvars.sh: Echoing weird variables.
3
4 var="'(]\\{}\$\""
5 echo $var # '(]\{}$"
6 echo "$var" # '(]\{}$" 和上面一句没什么不同.
7
8 echo
9
10 IFS='\'
11 echo $var # '(] {}$" \字符被空白符替换了,为什么?
12 echo "$var" # '(]\{}$"
13
14 exit 0
单引号(' ')和双引号类似,但它不允许解释变量引用,因此,在单引号内的字符$的特殊意思无效了。在单引号内,除了字符',每个特殊字符都只是字面的意思。单引号(全局引用)比双引号(部分引用)更严格的处理引用部分。
由于在单引号里的转义字符(\)也只是被局限于字面上的意思,所以想在一双单引号里再加单引号是不行的
1 echo "Why can't I write 's between single quotes"
2
3 echo
4
5 # The roundabout method.
6 echo 'Why can'\''t I write '"'"'s between single quotes'
7 # |-------| |----------| |-----------------------|
8 # 三个单引号引起的字符串之间有一个转义的单引号和一个由双引号引起的单引号.
注:
[1] 除非当前目录下有一个文件名为first的文件。那这是引用的另外一个不同的理由了。
[2] 这也会使变量的值会有副作用。(看下面的)
[3] 在命令行上,把感叹号"!"放在双引号里执行命令会出错(译者注:比如说:echo "hello!"). 因为感叹号被解释成了一个历史命令. 然而在一个脚本文件里,这么写则是正确的,因为在脚本文件里Bash的历史机制被禁用了。
在双号号里在字符"\"也会引起许多不一致的行为。
bash$ echo hello\!
hello!
bash$ echo "hello\!"
hello\!
bash$ echo -e x\ty
xty
bash$ echo -e "x\ty"
x y
[4] 句子的分割,在这里是指分割一个字符串为许多不连续的单独的参数.
5.2. 转义
转义是引用单字符的方法.在单个字符前面的转义符(\)告诉shell不必特殊解释这个字符,只把它当成字面上的意思。
但在一些命令和软件包里,比如说echo和sed,转义一个字符可能会引起一个相反的效果--因为它们可能触发那个字符的特殊意思。
一些转义字符的表示的特殊意思
- 和echo,sed连用时:
-
- \n
-
表示新行
- \r
-
表示回车
- \t
-
表示水平的制表符
- \v
-
表示垂直的制表符
- \b
-
表示后退符
- \a
-
表示“警告”(蜂鸣或是闪动)
- \0xx
-
翻译成ASCII码为八进制0xx所表示的字符
例子 5-2. 转义字符
1 #!/bin/bash
2 # escaped.sh: 转义字符
3
4 echo; echo
5
6 echo "\v\v\v\v" # 打印出 \v\v\v\v literally.
7 # 用带着选项-e的'echo'会打印出转义字符串.
8 echo "============="
9 echo "VERTICAL TABS"
10 echo -e "\v\v\v\v" # 打印四个垂直的制表符.
11 echo "=============="
12
13 echo "QUOTATION MARK"
14 echo -e "\042" # 打印出字符" (引号, 它的八进制ASCII码为42).
15 echo "=============="
16
17 # 当使用像$'\X'的结构时,-e选项是多余的.
18 echo; echo "NEWLINE AND BEEP"
19 echo $'\n' # 新行.
20 echo $'\a' # 警告 (蜂鸣).
21
22 echo "==============="
23 echo "QUOTATION MARKS"
24 # 版本2开始Bash已经允许使用$'\nnn'结构了.
25 # 注意在这里,'\nnn'表示一个八进制的值.
26 echo $'\t \042 \t' # Quote (") framed by tabs.
27
28 # 使用$'\xhhh'结构也可以使用十六进制数来转义.
29 echo $'\t \x22 \t' # Quote (") framed by tabs.
30 # 多谢Greg Keraunen指出这个..
31 # 早期的Bash版本允许用'\x022'.(译者注,现在不行了)
32 echo "==============="
33 echo
34
35
36 # 用ASCII码值把字符赋给变量.
37 # ----------------------------------------
38 quote=$'\042' # 引号"被赋给变量quote了.
39 echo "$quote This is a quoted string, $quote and this lies outside the quotes."
40
41 echo
42
43 # 用连串的ASCII码把一串字符赋给变量..
44 triple_underline=$'\137\137\137' # 137是字符'_'的ASCII码.
45 echo "$triple_underline UNDERLINE $triple_underline"
46
47 echo
48
49 ABC=$'\101\102\103\010' # 101, 102, 103分别是A, B, C字符的八进制ASCII码.
50 echo $ABC
51
52 echo; echo
53
54 escape=$'\033' # 033是ESC的ASCII码的八进制值
55 echo "\"escape\" echoes as $escape"
56 # 不可见的输出.
57
58 echo; echo
59
60 exit 0
参考扩展结构$' '的另外一个例子xample 34-1.
\"
表示引号(")的字面意思
1 echo "Hello" # Hello
2 echo "\"Hello\", he said." # "Hello", he said.
$
表示美元符($)的字面意思(如果在$跟上变量名将不会引用变量的值)
echo "\$variable01" # 输出是$variable01
\
表示反斜杠(\)的字面意思
1 echo "\\" # 输出是\
2
3 # 然而 . . .
4
5 echo "\" # 在命令行,这句将会打印SP2变量值(译者注:变量SP2是输入未完成提示符),并要求你继续输入..
6 # 在脚本文件里, 这句会出错.
反斜杠的作用要看它是否是自我转义,被引用,或出现在命令替换结构或是在here document里.
1 # 简单的转义和引用
2 echo \z # z
3 echo \\z # \z
4 echo '\z' # \z
5 echo '\\z' # \\z
6 echo "\z" # \z
7 echo "\\z" # \z
8
9 # 命令替换
10 echo `echo \z` # z
11 echo `echo \\z` # z
12 echo `echo \\\z` # \z
13 echo `echo \\\\z` # \z
14 echo `echo \\\\\\z` # \z
15 echo `echo \\\\\\\z` # \\z
16 echo `echo "\z"` # \z
17 echo `echo "\\z"` # \z
18
19 # Here document
20 cat <<EOF
21 \z
22 EOF # \z
23
24 cat <<EOF
25 \\z
26 EOF # \z
一个字符串赋给变量时里面的组成部分可能会被转义,但如果单独一个转义字符(\)是不能赋给变量的。
1 variable=\
2 echo "$variable"
3 # 不能工作 - 给出一个错误信息:
4 # test.sh: : command not found
5 # 单独一个转义字符是不能正确地赋给变量的.
6 #
7 # 那上面语句究竟发生了什么呢?实际上转义符"\"转义了新行符,
8 #+ 产生的作用如同 variable=echo "$variable"
9 #+ 而这是无效的变量赋值
10
11 variable=\
12 23skidoo
13 echo "$variable" # 23skidoo
14 # 这样就能工作,因为第二行的变量赋值是有效的
15 #
16
17 variable=\
18 # \^ 转义后面的空格(译者注:粗心的读者一定要注意上面最后的空格)
19 echo "$variable" # 空格
20
21 variable=\\
22 echo "$variable" # \
23
24 variable=\\\
25 echo "$variable"
26 # 不能工作 - 产生一个错误:
27 # test.sh: \: command not found
28 #
29 # 第一个\转义第二个\,结果只剩单独的第三个\字符,
30 #+ 这样又会发生上面的情况.
31
32 variable=\\\\
33 echo "$variable" # \\
34 # 第二和第四个\字符被转义.
35 # 这样不会出错了.
转义一个空格可以防止一个字符串参数被分割成多个命令行参数。
1 file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7"
2 # 文件列表作为参数传递给命令.
3
4 # 再加两个参数给命令ls,一同列出文件信息.
5 ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_list
6
7 echo "-------------------------------------------------------------------------"
8
9 # 如果我们转义上面的一对空格会发生什么?
10 ls -l /usr/X11R6/bin/xsetroot\ /sbin/dump\ $file_list
11 # 出错: 开头的三个文件名被连成一个文件名并传递给了命令'ls -l'
12 # 因为两个转义字符禁止了空格分割参数的作用。
转义符也提供了写一个多行命令的手段。一般地,每个单独的行有一个不同的命令,而在一行末尾的转义符转义新行符,命令序列则由下一行继续。
1 (cd /source/directory && tar cf - . ) | \
2 (cd /dest/directory && tar xpvf -)
3 # 把Alan Cox目录树全部复制到另外一个目录里,
4 # 但分为两行可以增加可读性.
5
6 # 你也可以用下面的命令达到一样的效果:
7 tar cf - -C /source/directory . |
8 tar xpvf - -C /dest/directory
如果一个脚本行用一个管道线"|"结束行尾,后面可以再跟一个不必一定要的转义符"\"。然而,好的编程习惯最好加上一个转义符“\”。
1 echo "foo
2 bar"
3 #foo
4 #bar
5
6 echo
7
8 echo 'foo
9 bar' # 没什么不同.
10 #foo
11 #bar
12
13 echo
14
15 echo foo\
16 bar # 新行符被转义.
17 #foobar
18
19 echo
20
21 echo "foo\
22 bar" # 还是一样,字符\在弱引用中还是被解释为转义字符
23 #foobar
24
25 echo
26
27 echo 'foo\
28 bar' # 由于转义符"\"在强引用符里,所以只能解释为字面上的意思
29 #foo\
30 #bar
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律