# 5.2 轉義
轉義是一種引用單字符的方法。通過在特殊字符前加上轉義符 `\` 來告訴shell按照字面意思去解釋這個字符。
>  需要注意的是,在一些特定的命令和工具,比如 `echo` 和 `sed` 中,轉義字符通常會起到相反的效果,即可能會使得那些字符產生特殊含義。
在 `echo` 與 `sed` 命令中,轉義字符的特殊含義
### \n
換行(line feed)。
### \r
回車(carriage return)。
### \t
水平制表符。
### \v
垂直制表符。
### \b
退格。
### \a
警報、響鈴或閃爍。
### \0xx
ASCII碼的八進制形式,等價于 `0nn`,其中 `nn` 是數字。
>  在 `$' ... '` 字符串擴展結構中可以通過轉義八進制或十六進制的ASCII碼形式給變量賦值,比如 `quote=$'\042'`。
樣例 5-2. 轉義字符
```bash
#!/bin/bash
# escaped.sh: 轉義字符
##############################################
### 首先讓我們先看一下轉義字符的基本用法。 ###
##############################################
# 轉義新的一行。
# ------------
echo ""
echo "This will print
as two lines."
# This will print
# as two lines.
echo "This will print \
as one line."
# This will print as one line.
echo; echo
echo "============="
echo "\v\v\v\v" # 按字面意思打印 \v\v\v\v
# 使用 echo 命令的 -e 選項來打印轉義字符。
echo "============="
echo "VERTICAL TABS"
echo -e "\v\v\v\v" # 打印四個垂直制表符。
echo "=============="
echo "QUOTATION MARK"
echo -e "\042" # 打印 " (引號,八進制ASCII碼為42)。
echo "=============="
# 使用 $'\X' 這樣的形式后可以不需要加 -e 選項。
echo; echo "NEWLINE and (maybe) BEEP"
echo $'\n' # 新的一行。
echo $'\a' # 警報(響鈴)。
# 根據不同的終端版本,也可能是閃屏。
# 我們之前介紹了 $'\nnn' 字符串擴展,而現在我們要看到的是...
# ============================================ #
# 自 Bash 第二個版本開始的 $'\nnn' 字符串擴展結構。
# ============================================ #
echo "Introducing the \$\' ... \' string-expansion construct . . . "
echo ". . . featuring more quotation marks."
echo $'\t \042 \t' # 在制表符之間的引號。
# 需要注意的是 '\nnn' 是一個八進制的值。
# 字符串擴展同樣適用于十六進制的值,格式是 $'\xhhh'。
echo $'\t \x22 \t' # 在制表符之間的引號。
# 感謝 Greg Keraunen 指出這些。
# 在早期的 Bash 版本中允許使用 '\x022' 這樣的形式。
echo
# 將 ASCII 碼字符賦值給變量。
# -----------------------
quote=$'\042' # 將 " 賦值給變量。
echo "$quote Quoted string $quote and this lies outside the quotes."
echo
# 連接多個 ASCII 碼字符給變量。
triple_underline=$'\137\137\137' # 137是 '_' ASCII碼的八進制形式
echo "$triple_underline UNDERLINE $triple_underline"
echo
ABC=$'\101\102\103\010' # 101,102,103是 A, B, C
# ASCII碼的八進制形式。
echo $ABC
echo
escape=$'\033' # 033 是 ESC 的八進制形式
echo "\"escape\" echoes an $escape"
# 沒有可見輸出
echo
exit 0
```
下面是一個更加復雜的例子:
樣例 5-3. 檢測鍵盤輸入
```bash
#!/bin/bash
# 作者:Sigurd Solaas,作于2011年4月20日
# 授權在《高級Bash腳本編程指南》中使用。
# 需要 Bash 版本高于4.2。
key="no value yet"
while true; do
clear
echo "Bash Extra Keys Demo. Keys to try:"
echo
echo "* Insert, Delete, Home, End, Page_Up and Page_Down"
echo "* The four arrow keys"
echo "* Tab, enter, escape, and space key"
echo "* The letter and number keys, etc."
echo
echo " d = show date/time"
echo " q = quit"
echo "================================"
echo
# 將獨立的Home鍵值轉換為數字7上的Home鍵值:
if [ "$key" = $'\x1b\x4f\x48' ]; then
key=$'\x1b\x5b\x31\x7e'
# 引用字符擴展結構。
fi
# 將獨立的End鍵值轉換為數字1上的End鍵值:
if [ "$key" = $'\x1b\x4f\x46' ]; then
key=$'\x1b\x5b\x34\x7e'
fi
case "$key" in
$'\x1b\x5b\x32\x7e') # 插入
echo Insert Key
;;
$'\x1b\x5b\x33\x7e') # 刪除
echo Delete Key
;;
$'\x1b\x5b\x31\x7e') # 數字7上的Home鍵
echo Home Key
;;
$'\x1b\x5b\x34\x7e') # 數字1上的End鍵
echo End Key
;;
$'\x1b\x5b\x35\x7e') # 上翻頁
echo Page_Up
;;
$'\x1b\x5b\x36\x7e') # 下翻頁
echo Page_Down
;;
$'\x1b\x5b\x41') # 上箭頭
echo Up arrow
;;
$'\x1b\x5b\x42') # 下箭頭
echo Down arrow
;;
$'\x1b\x5b\x43') # 右箭頭
echo Right arrow
;;
$'\x1b\x5b\x44') # 左箭頭
echo Left arrow
;;
$'\x09') # 制表符
echo Tab Key
;;
$'\x0a') # 回車
echo Enter Key
;;
$'\x1b') # ESC
echo Escape Key
;;
$'\x20') # 空格
echo Space Key
;;
d)
date
;;
q)
echo Time to quit...
echo
exit 0
;;
*)
echo Your pressed: \'"$key"\'
;;
esac
echo
echo "================================"
unset K1 K2 K3
read -s -N1 -p "Press a key: "
K1="$REPLY"
read -s -N2 -t 0.001
K2="$REPLY"
read -s -N1 -t 0.001
K3="$REPLY"
key="$K1$K2$K3"
done
exit $?
```
還可以查看樣例 37-1。
### \\"
轉義引號,指代自身。
```bash
echo "Hello" # Hello
echo "\"Hello\" ... he said." # "Hello" ... he said.
```
### \\$
轉義美元符號(跟在 `\\$` 后的變量名將不會被引用)。
```bash
echo "\$variable01" # $variable01
echo "The book cost \$7.98." # The book cost $7.98.
```
### \\\\
轉義反斜杠,指代自身。
```bash
echo "\\" # 結果是 \
# 然而...
echo "\" # 在命令行中會出現第二行并提示輸入。
# 在腳本中會出錯。
# 但是...
echo '\' # 結果是 \
```
>  根據轉義符所在的上下文(強引用、弱引用,命令替換或者在 here document)的不同,它的行為也會有所不同。
>
```bash
# 簡單轉義與引用
echo \z # z
echo \\z # \z
echo '\z' # \z
ehco '\\z' # \\z
echo "\z" # \z
echo "\\z" # \z
>
# 命令替換
echo `echo \z` # z
echo `echo \\z` # z
echo `echo \\\z` # \z
echo `echo \\\\z` # \z
echo `echo \\\\\\z` # \z
echo `echo \\\\\\\z` # \\z
echo `echo "\z"` # \z
echo `echo "\\z"` # \z
>
# Here Document
cat <<EOF
\z
EOF # \z
>
cat <<EOF
\\z
EOF # \z
>
# 以上例子由 Stéphane Chazelas 提供。
```
> 含有轉義字符的字符串可以賦值給變量,但是僅僅將單一的轉義符賦值給變量是不可行的。
>
```bash
variable=\
echo "$variable"
# 這樣做會報如下錯誤:
# tesh.sh: : command not found
# 單獨的轉義符不能夠賦值給變量。
#
# 事實上,"\" 轉義了換行,實際效果是:
#+ variable=echo "$variable"
#+ 這是一個非法的賦值方式。
>
variable=\
23skidoo
echo "$variable" # 23skidoo
# 因為第二行是一個合法的賦值,因此不會報錯。
>
variable=\
# \^ 轉義符后有一個空格
echo "$variable" # 空格
>
variable=\\
echo "$variable" # \
>
variable=\\\
echo "$variable"
# 這樣做會報如下錯誤:
# tesh.sh: \: command not found
#
# 第一個轉義符轉轉義了第二個,但是第三個轉義符仍舊轉義的是換行,
#+ 跟開始的那個例子一樣,因此會報錯。
>
variable=\\\\
echo "$variable" # \\
# 第二個和第四個轉義符被轉義了,因此可行。
```
轉義空格能夠避免在命令參數列表中的字符分割問題。
```bash
file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7"
# 將一系列文件作為命令的參數。
# 增加兩個文件到列表中,并且列出整個表。
ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_list
echo "-------------------------------------------------------------------------"
# 如果我們轉義了這些空格會怎樣?
ls -l /usr/X11R6/bin/xsetroot\ /sbin/dump\ $file_list
# 錯誤:因為轉義了兩個空格,因此前三個文件被連接成了一個參數傳遞給了 'ls -l'
```
轉義符也提供一種可以撰寫多行命令的方式。通常,每一行是一個命令,但是轉義換行后命令就可以在下一行繼續撰寫。
```bash
(cd /source/directory && tar cf - . ) | \
(cd /dest/directory && tar xpvf -)
# 回顧 Alan Cox 的目錄樹拷貝命令,但是把它拆成了兩行。
# 或者你也可以:
tar cf - -C /source/directory . |
tar xpvf - -C /dest/directory
# 可以看下方的注釋。
# (感謝 Stéphane Chazelas。)
```
>  在腳本中,如果以 "|" 管道作為一行的結束字符,那么不需要加轉義符 \ 也可以寫多行命令。但是一個好的編程習慣就是在寫多行命令的事后,無論什么情況都要在行尾加上轉義符 \。
```bash
echo "foo
bar"
#foo
#bar
echo
echo 'foo
bar' # 沒有區別。
#foo
#bar
echo
echo foo\
bar # 轉義換行。
#foobar
echo
echo "foo\
bar" # 沒有區別,在弱引用中,\ 轉義符仍舊轉義了換行。
#foobar
echo
echo 'foo\
bar' # 在強引用中,\ 就按照字面意思來解釋了。
#foo\
#bar
# 由 Stéphane Chazelas 提供的例子。
```
- 第一部分 初見shell
- 1. 為什么使用shell編程
- 2. 和Sha-Bang(#!)一起出發
- 2.1 調用一個腳本
- 2.2 牛刀小試
- 第二部分 shell基礎
- 3. 特殊字符
- 4. 變量與參數
- 4.1 變量替換
- 4.2 變量賦值
- 4.3 Bash弱類型變量
- 4.4 特殊變量類型
- 5. 引用
- 5.1 引用變量
- 5.2 轉義
- 6. 退出與退出狀態
- 7. 測試
- 7.1 測試結構
- 7.2 文件測試操作
- 7.3 其他比較操作
- 7.4 嵌套 if/then 條件測試
- 7.5 牛刀小試
- 8. 運算符相關話題
- 8.1 運算符
- 8.2 數字常量
- 8.3 雙圓括號結構
- 8.4 運算符優先級
- 第三部分 shell進階
- 10. 變量處理
- 10.1 字符串處理
- 10.1.1 使用 awk 處理字符串
- 10.1.2 參考資料
- 10.2 參數替換
- 11. 循環與分支
- 11.1 循環
- 11.2 嵌套循環
- 11.3 循環控制
- 11.4 測試與分支
- 12. 命令替換
- 13. 算術擴展
- 14. 休息時間
- 第五部分 進階話題
- 19. 嵌入文檔
- 20. I/O 重定向
- 20.1 使用 exec
- 20.2 重定向代碼塊
- 20.3 應用程序
- 22. 限制模式的Shell
- 23. 進程替換
- 26. 列表結構
- 25. 別名