5. 引用 - 5.2 转义

优质
小牛编辑
124浏览
2023-12-01

转义是一种引用单字符的方法。通过在特殊字符前加上转义符 来告诉shell按照字面意思去解释这个字符。

需要注意的是,在一些特定的命令和工具,比如 echosed 中,转义字符通常会起到相反的效果,即可能会使得那些字符产生特殊含义。

echosed 命令中,转义字符的特殊含义

n

换行(line feed)。

r

回车(carriage return)。

t

水平制表符。

v

垂直制表符。

b

退格。

a

警报、响铃或闪烁。

xx

ASCII码的八进制形式,等价于 0nn,其中 nn 是数字。

$' ... ' 字符串扩展结构中可以通过转义八进制或十六进制的ASCII码形式给变量赋值,比如 quote=$'42'

样例 5-2. 转义字符

  1. #!/bin/bash
  2. # escaped.sh: 转义字符
  3. ##############################################
  4. ### 首先让我们先看一下转义字符的基本用法。 ###
  5. ##############################################
  6. # 转义新的一行。
  7. # ------------
  8. echo ""
  9. echo "This will print
  10. as two lines."
  11. # This will print
  12. # as two lines.
  13. echo "This will print
  14. as one line."
  15. # This will print as one line.
  16. echo; echo
  17. echo "============="
  18. echo "vvvv" # 按字面意思打印 vvvv
  19. # 使用 echo 命令的 -e 选项来打印转义字符。
  20. echo "============="
  21. echo "VERTICAL TABS"
  22. echo -e "vvvv" # 打印四个垂直制表符。
  23. echo "=============="
  24. echo "QUOTATION MARK"
  25. echo -e "42" # 打印 " (引号,八进制ASCII码为42)。
  26. echo "=============="
  27. # 使用 $'X' 这样的形式后可以不需要加 -e 选项。
  28. echo; echo "NEWLINE and (maybe) BEEP"
  29. echo $'n' # 新的一行。
  30. echo $'a' # 警报(响铃)。
  31. # 根据不同的终端版本,也可能是闪屏。
  32. # 我们之前介绍了 $'nnn' 字符串扩展,而现在我们要看到的是...
  33. # ============================================ #
  34. # 自 Bash 第二个版本开始的 $'nnn' 字符串扩展结构。
  35. # ============================================ #
  36. echo "Introducing the $' ... ' string-expansion construct . . . "
  37. echo ". . . featuring more quotation marks."
  38. echo $'t 42 t' # 在制表符之间的引号。
  39. # 需要注意的是 'nnn' 是一个八进制的值。
  40. # 字符串扩展同样适用于十六进制的值,格式是 $'xhhh'。
  41. echo $'t x22 t' # 在制表符之间的引号。
  42. # 感谢 Greg Keraunen 指出这些。
  43. # 在早期的 Bash 版本中允许使用 'x022' 这样的形式。
  44. echo
  45. # 将 ASCII 码字符赋值给变量。
  46. # -----------------------
  47. quote=$'42' # 将 " 赋值给变量。
  48. echo "$quote Quoted string $quote and this lies outside the quotes."
  49. echo
  50. # 连接多个 ASCII 码字符给变量。
  51. triple_underline=$'137137137' # 137是 '_' ASCII码的八进制形式
  52. echo "$triple_underline UNDERLINE $triple_underline"
  53. echo
  54. ABC=$'10110210310' # 101,102,103是 A, B, C
  55. # ASCII码的八进制形式。
  56. echo $ABC
  57. echo
  58. escape=$'33' # 033 是 ESC 的八进制形式
  59. echo ""escape" echoes an $escape"
  60. # 没有可见输出
  61. echo
  62. exit 0

下面是一个更加复杂的例子:

样例 5-3. 检测键盘输入

  1. #!/bin/bash
  2. # 作者:Sigurd Solaas,作于2011年4月20日
  3. # 授权在《高级Bash脚本编程指南》中使用。
  4. # 需要 Bash 版本高于4.2。
  5. key="no value yet"
  6. while true; do
  7. clear
  8. echo "Bash Extra Keys Demo. Keys to try:"
  9. echo
  10. echo "* Insert, Delete, Home, End, Page_Up and Page_Down"
  11. echo "* The four arrow keys"
  12. echo "* Tab, enter, escape, and space key"
  13. echo "* The letter and number keys, etc."
  14. echo
  15. echo " d = show date/time"
  16. echo " q = quit"
  17. echo "================================"
  18. echo
  19. # 将独立的Home键值转换为数字7上的Home键值:
  20. if [ "$key" = $'x1bx4fx48' ]; then
  21. key=$'x1bx5bx31x7e'
  22. # 引用字符扩展结构。
  23. fi
  24. # 将独立的End键值转换为数字1上的End键值:
  25. if [ "$key" = $'x1bx4fx46' ]; then
  26. key=$'x1bx5bx34x7e'
  27. fi
  28. case "$key" in
  29. $'x1bx5bx32x7e') # 插入
  30. echo Insert Key
  31. ;;
  32. $'x1bx5bx33x7e') # 删除
  33. echo Delete Key
  34. ;;
  35. $'x1bx5bx31x7e') # 数字7上的Home键
  36. echo Home Key
  37. ;;
  38. $'x1bx5bx34x7e') # 数字1上的End键
  39. echo End Key
  40. ;;
  41. $'x1bx5bx35x7e') # 上翻页
  42. echo Page_Up
  43. ;;
  44. $'x1bx5bx36x7e') # 下翻页
  45. echo Page_Down
  46. ;;
  47. $'x1bx5bx41') # 上箭头
  48. echo Up arrow
  49. ;;
  50. $'x1bx5bx42') # 下箭头
  51. echo Down arrow
  52. ;;
  53. $'x1bx5bx43') # 右箭头
  54. echo Right arrow
  55. ;;
  56. $'x1bx5bx44') # 左箭头
  57. echo Left arrow
  58. ;;
  59. $'x09') # 制表符
  60. echo Tab Key
  61. ;;
  62. $'x0a') # 回车
  63. echo Enter Key
  64. ;;
  65. $'x1b') # ESC
  66. echo Escape Key
  67. ;;
  68. $'x20') # 空格
  69. echo Space Key
  70. ;;
  71. d)
  72. date
  73. ;;
  74. q)
  75. echo Time to quit...
  76. echo
  77. exit 0
  78. ;;
  79. *)
  80. echo Your pressed: '"$key"'
  81. ;;
  82. esac
  83. echo
  84. echo "================================"
  85. unset K1 K2 K3
  86. read -s -N1 -p "Press a key: "
  87. K1="$REPLY"
  88. read -s -N2 -t 0.001
  89. K2="$REPLY"
  90. read -s -N1 -t 0.001
  91. K3="$REPLY"
  92. key="$K1$K2$K3"
  93. done
  94. exit $?

还可以查看样例 37-1。

转义引号,指代自身。

  1. echo "Hello" # Hello
  2. echo ""Hello" ... he said." # "Hello" ... he said.

$

转义美元符号(跟在 \$ 后的变量名将不会被引用)。

  1. echo "$variable01" # $variable01
  2. echo "The book cost $7.98." # The book cost $7.98.

\

转义反斜杠,指代自身。

  1. echo "\" # 结果是
  2. # 然而...
  3. echo "" # 在命令行中会出现第二行并提示输入。
  4. # 在脚本中会出错。
  5. # 但是...
  6. echo '' # 结果是

根据转义符所在的上下文(强引用、弱引用,命令替换或者在 here document)的不同,它的行为也会有所不同。

  1. # 简单转义与引用
  2. echo z # z
  3. echo \z # z
  4. echo 'z' # z
  5. ehco '\z' # \z
  6. echo "z" # z
  7. echo "\z" # z
  8. # 命令替换
  9. echo `echo z` # z
  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. # Here Document
  18. cat <<EOF
  19. z
  20. EOF # z
  21. cat <<EOF
  22. \z
  23. EOF # z
  24. # 以上例子由 Stéphane Chazelas 提供。

含有转义字符的字符串可以赋值给变量,但是仅仅将单一的转义符赋值给变量是不可行的。

  1. variable=
  2. echo "$variable"
  3. # 这样做会报如下错误:
  4. # tesh.sh: : command not found
  5. # 单独的转义符不能够赋值给变量。
  6. #
  7. # 事实上,"" 转义了换行,实际效果是:
  8. #+ variable=echo "$variable"
  9. #+ 这是一个非法的赋值方式。
  10. variable=
  11. 23skidoo
  12. echo "$variable" # 23skidoo
  13. # 因为第二行是一个合法的赋值,因此不会报错。
  14. variable=
  15. # ^ 转义符后有一个空格
  16. echo "$variable" # 空格
  17. variable=\
  18. echo "$variable" #
  19. variable=\
  20. echo "$variable"
  21. # 这样做会报如下错误:
  22. # tesh.sh: : command not found
  23. #
  24. # 第一个转义符转转义了第二个,但是第三个转义符仍旧转义的是换行,
  25. #+ 跟开始的那个例子一样,因此会报错。
  26. variable=\\
  27. echo "$variable" # \
  28. # 第二个和第四个转义符被转义了,因此可行。

转义空格能够避免在命令参数列表中的字符分割问题。

  1. file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7"
  2. # 将一系列文件作为命令的参数。
  3. # 增加两个文件到列表中,并且列出整个表。
  4. ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_list
  5. echo "-------------------------------------------------------------------------"
  6. # 如果我们转义了这些空格会怎样?
  7. ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_list
  8. # 错误:因为转义了两个空格,因此前三个文件被连接成了一个参数传递给了 'ls -l'

转义符也提供一种可以撰写多行命令的方式。通常,每一行是一个命令,但是转义换行后命令就可以在下一行继续撰写。

  1. (cd /source/directory && tar cf - . ) |
  2. (cd /dest/directory && tar xpvf -)
  3. # 回顾 Alan Cox 的目录树拷贝命令,但是把它拆成了两行。
  4. # 或者你也可以:
  5. tar cf - -C /source/directory . |
  6. tar xpvf - -C /dest/directory
  7. # 可以看下方的注释。
  8. # (感谢 Stéphane Chazelas。)

在脚本中,如果以 “|” 管道作为一行的结束字符,那么不需要加转义符 也可以写多行命令。但是一个好的编程习惯就是在写多行命令的事后,无论什么情况都要在行尾加上转义符 。

  1. echo "foo
  2. bar"
  3. #foo
  4. #bar
  5. echo
  6. echo 'foo
  7. bar' # 没有区别。
  8. #foo
  9. #bar
  10. echo
  11. echo foo
  12. bar # 转义换行。
  13. #foobar
  14. echo
  15. echo "foo
  16. bar" # 没有区别,在弱引用中, 转义符仍旧转义了换行。
  17. #foobar
  18. echo
  19. echo 'foo
  20. bar' # 在强引用中, 就按照字面意思来解释了。
  21. #foo
  22. #bar
  23. # 由 Stéphane Chazelas 提供的例子。