Skip to content

Latest commit

 

History

History
551 lines (421 loc) · 16.3 KB

ch5-2.md

File metadata and controls

551 lines (421 loc) · 16.3 KB

5.2. Escaping

第五章第二節:跳脫

Escaping is a method of quoting single characters.

"跳脫" (Escaping,亦稱:"脫逸"、"逸出",下文統稱 "跳脫") 是一個引用單一字元的方法。

The escape (\) preceding a character tells the shell to interpret that character literally.

寫在某一個字元之前的跳脫字元 (\) 將告訴 shell 以字面上的原意解讀該字元。

Note: With certain commands and utilities, such as echo and sed, escaping a character may have the opposite effect - it can toggle on a special meaning for that character.

注意:部份指令與工具,例如 echo 與 sed,對於跳脫某一字元可能會得到反效果 ─ 它可以觸發該字元的特殊意義。

Special meanings of certain escaped characters

部份字元跳脫後的特殊意義

used with echo and sed

搭配 "echo" 與 "sed" 指令使用

\n means newline

\n 表示換行字元

\r means return

\r 表示歸位字元

\t means tab

\t 表示(水平)定位字元 (tab)

\v means vertical tab

\v 表示垂直定位字元 (vertical tab)

\b means backspace

\b 表示退格字元 (backspace)

\a means alert (beep or flash)

\a 表示警示字元 (可能有嗶聲或畫面閃爍的效果)

\0xx translates to the octal ASCII equivalent of 0nn, where nn is a string of digits

\0xx 將轉譯成如同 ASCII 八進制表示式 0nn 所表示的數字,其中 nn 為數字字串

Note: The $' ... ' quoted string-expansion construct is a mechanism that uses escaped octal or hex values to assign ASCII characters to variables, e.g., quote=$'\042'.

注意:「$' ... '」此種特殊的 quoted string-expansion (引用字串展開結構),是一種使用跳脫後的八進制或十六進制值,將其所代表的 ASCII 字元賦值於變數的機制,例如「quote=$'\042'」(類似 ANSI C 的跳脫序列)

Example 5-2. Escaped Characters

範例 5-2. 跳脫後的字元

#!/bin/bash
# escaped.sh: escaped characters
# escaped.sh: 跳脫後的字元

#############################################################
### First, let's show some basic escaped-character usage. ###
### 首先,我們來展示一些基本的跳脫後的字元用法。          ###
#############################################################

# Escaping a newline.
# 跳脫一個換行字元。
# ------------------

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"      # Prints \v\v\v\v literally.
                     # 印出 \v\v\v\v 原文。
# Use the -e option with 'echo' to print escaped characters.
# 使用 'echo' 指令搭配 -e 參數,可印出跳脫後的字元。

echo "============="
echo "VERTICAL TABS"
echo -e "\v\v\v\v"   # Prints 4 vertical tabs.
                     # 印出 4 個垂直定位字元。
echo "=============="

echo "QUOTATION MARK"
echo -e "\042"       # Prints " (quote, octal ASCII character 42).
                     # 印出 " (雙引號字元的確是八進制 ASCII 字元 42)。
echo "=============="



# The $'\X' construct makes the -e option unnecessary.
# $'\X' 結構使得 -e 選項參數變得不再那麼必要了。

echo; echo "NEWLINE and (maybe) BEEP"
echo $'\n'           # Newline.
                     # 換行字元。
echo $'\a'           # Alert (beep).
                     # 警示字元 (嗶聲)。
                     # May only flash, not beep, depending on terminal.
                     # 也許可能只有畫面閃一下,而並沒有嗶聲,看你的終端機設定。

# We have seen $'\nnn' string expansion, and now . . .
# 我們已經看過 $'\nnn' 字串展開結構,現在接著是 . . .

# =================================================================== #
# Version 2 of Bash introduced the $'\nnn' string expansion construct.
# Bash 第 2 版開始導入 $'\nnn' 字串展開結構支援。
# =================================================================== #

echo "Introducing the \$\' ... \' string-expansion construct . . . "
echo ". . . featuring more quotation marks."

echo $'\t \042 \t'   # Quote (") framed by tabs.
                     # 以定位字元 (tab) 包住雙引號字元 (")。
# Note that  '\nnn' is an octal value.
# 注意:此 '\nnn' 是一個八進制值。

# It also works with hexadecimal values, in an $'\xhhh' construct.
# 使用 $'\xhhh' 結構,十六進制值也能使用。
echo $'\t \x22 \t'  # Quote (") framed by tabs.
                    # 以定位字元 (tab) 包住雙引號字元 (")。
# Thank you, Greg Keraunen, for pointing this out.
# 感謝 Greg Keraunen 指出這一點。
# Earlier Bash versions allowed '\x022'.
# 較早期版本的 Bash 允許直接使用 '\x022' 這種格式。

echo


# Assigning ASCII characters to a variable.
# 將 ASCII 字元賦值到一個變數。
# ----------------------------------------
quote=$'\042'        # " assigned to a variable.
                     # 將雙引號 " 賦值到一個變數。
echo "$quote Quoted string $quote and this lies outside the quotes."

echo

# Concatenating ASCII chars in a variable.
# 在同個變數中串接多個 ASCII 字元。
triple_underline=$'\137\137\137'  # 137 is octal ASCII code for '_'.
                                  # 137 為底線字元 '_' 的八進制 ASCII code。
echo "$triple_underline UNDERLINE $triple_underline"

echo

ABC=$'\101\102\103\010'           # 101, 102, 103 are octal A, B, C.
                                  # 101, 102, 103 為 A, B, C 的八進制值。
echo $ABC

echo

escape=$'\033'                    # 033 is octal for escape.
                                  # 033 為跳脫字元的八進制值。
echo "\"escape\" echoes as $escape"
#                                   no visible output.
#                                   看不見的輸出字元。

echo

exit 0

A more elaborate example:

一個更複雜的範例:

Example 5-3. Detecting key-presses

範例 5-3. 偵測鍵盤按鍵

#!/bin/bash
# Author: Sigurd Solaas, 20 Apr 2011
# 作者:Sigurd Solaas, 2011年4月20日
# Used in ABS Guide with permission.
# 允許用於 ABS 指南。
# Requires version 4.2+ of Bash.
# 需要 Bash 4.2+ 以上的版本。

key="no value yet"
while true; do
  clear
  echo "Bash Extra Keys Demo. Keys to try:"
  echo "(Bash 額外的按鍵展示。待試按鍵:)"
  echo
  echo "* Insert, Delete, Home, End, Page_Up and Page_Down"
  echo "  (插入、刪除、Home、End、上頁、下頁)"
  echo "* The four arrow keys"
  echo "  (四個方向鍵)"
  echo "* Tab, enter, escape, and space key"
  echo "  (Tab、Enter、Esc、以及空格鍵)"
  echo "* The letter and number keys, etc."
  echo "  (英文字母與數字鍵,等。)"
  echo
  echo "    d = show date/time"
  echo "        顯示日期時間"
  echo "    q = quit"
  echo "        離開"
  echo "================================"
  echo

  # Convert the separate home-key to home-key_num_7:
  # 將各個的 Home 鍵換成 home-key_num_7:
  if [ "$key" = $'\x1b\x4f\x48' ]; then
    key=$'\x1b\x5b\x31\x7e'
    #   Quoted string-expansion construct.
    #   Quoted string-expansion 引用字串展開結構。(支援類似 ANSI C 的跳脫序列)
  fi

  # Convert the separate end-key to end-key_num_1.
  # 將各個的 End 鍵換成 end-key_num_1:
  if [ "$key" = $'\x1b\x4f\x46' ]; then
    key=$'\x1b\x5b\x34\x7e'
  fi

  case "$key" in
    $'\x1b\x5b\x32\x7e')  # Insert
      echo Insert Key
    ;;
    $'\x1b\x5b\x33\x7e')  # Delete
      echo Delete Key
    ;;
    $'\x1b\x5b\x31\x7e')  # Home_key_num_7
      echo Home Key
    ;;
    $'\x1b\x5b\x34\x7e')  # End_key_num_1
      echo End Key
    ;;
    $'\x1b\x5b\x35\x7e')  # Page_Up
      echo Page_Up
    ;;
    $'\x1b\x5b\x36\x7e')  # Page_Down
      echo Page_Down
    ;;
    $'\x1b\x5b\x41')  # Up_arrow
      echo Up arrow
    ;;
    $'\x1b\x5b\x42')  # Down_arrow
      echo Down arrow
    ;;
    $'\x1b\x5b\x43')  # Right_arrow
      echo Right arrow
    ;;
    $'\x1b\x5b\x44')  # Left_arrow
      echo Left arrow
    ;;
    $'\x09')  # Tab
      echo Tab Key
    ;;
    $'\x0a')  # Enter
      echo Enter Key
    ;;
    $'\x1b')  # Escape
      echo Escape Key
    ;;
    $'\x20')  # Space
      echo Space Key
    ;;
    d)
      date
    ;;
    q)
      echo Time to quit...
      echo
      exit 0
    ;;
    *)
      echo You 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 $?

See also Example 37-1.

可另行參閱:範例 37-1. 字串展開。

\" gives the quote its literal meaning

\" 給予雙引號字面上的原意

echo "Hello"                     # Hello
echo "\"Hello\" ... he said."    # "Hello" ... he said.

\$ gives the dollar sign its literal meaning (variable name following \$ will not be referenced)

\$ 給予錢字號字面上的原意 (名稱接於其後的變數將不會被參考到)

echo "\$variable01"           # $variable01
echo "The book cost \$7.98."  # The book cost $7.98.

\\ gives the backslash its literal meaning

\\ 給予反斜線字面上的原意

echo "\\"  # Results in \
           # 結果為 \

# Whereas . . .
# 然而 . . .

echo "\"   # Invokes secondary prompt from the command-line.
           # 若鍵入命令列中執行,則會喚起第二層命令列提示。
           # In a script, gives an error message.
           # 若寫於腳本中,則會得到錯誤訊息。

# However . . .
# 不過 . . .

echo '\'   # Results in \
           # 結果亦為 \

Note: The behavior of \ depends on whether it is escaped, strong-quoted, weak-quoted, or appearing within command substitution or a here document.

注意:反斜線 \ 的效果,取決於它是否跳脫過、強引用(單引號包住)、弱引用(雙引號包住)、或著出現在指令替換、here document 裡面。

                      #  Simple escaping and quoting
                      #  簡單的跳脫與引號包住
echo \z               #  z
echo \\z              # \z
echo '\z'             # \z
echo '\\z'            # \\z
echo "\z"             # \z
echo "\\z"            # \z

                      #  Command substitution
                      #  指令替換
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

# These examples supplied by Stéphane Chazelas.
# 感謝 Stéphane Chazelas 提供上述範例。

Elements of a string assigned to a variable may be escaped, but the escape character alone may not be assigned to a variable.

被賦值到一個變數的字串之內容元素可能是跳脫後的,但僅含跳脫字元時賦值會失敗。

variable=\
echo "$variable"
# Will not work - gives an error message:
# 將無法正常動作 - 印出一個錯誤訊息:
# test.sh: : command not found
# A "naked" escape cannot safely be assigned to a variable.
# 一個 "赤裸的" 跳脫字元是無法被安全地賦值到一個變數裡。
#
#  What actually happens here is that the "\" escapes the newline and
#+ the effect is       variable=echo "$variable"
#+                     invalid variable assignment
# 這裡實際發生的事情為那個反斜線 "\" 跳脫了換行字元,
# 並且那兩行等效於「variable=echo "$variable"」為一無效的變數賦值。

variable=\
23skidoo
echo "$variable"        #  23skidoo
                        #  This works, since the second line
                        #  這個可正常動作,因為第二行
                        #+ is a valid variable assignment.
                        #+ 為一有效的變數賦值。

variable=\ 
#        \^    escape followed by space
#              注意跳脫字元後面有接著一個空格字元
echo "$variable"        # space
                        # 空白

variable=\\
echo "$variable"        # \
                        # 一個跳脫字元 (\)

variable=\\\
echo "$variable"
# Will not work - gives an error message:
# 將無法正常動作 - 並且印出一個錯誤訊息:
# test.sh: \: command not found
#
#  First escape escapes second one, but the third one is left "naked",
#  第一個跳脫字元跳脫了第二個,但留下 "赤裸的" 第三個在那(沒人幫忙跳脫)。
#+ with same result as first instance, above.
#+ 如同前述的第一個例子的結果一樣。

variable=\\\\
echo "$variable"        # \\
                        # Second and fourth escapes escaped.
                        # 第二個跟第四個跳脫字元都有被跳脫。
                        # This is o.k.
                        # 這樣很 o.k.

Escaping a space can prevent word splitting in a command's argument list.

把空格字元給跳脫掉可以預防指令的參數列表發生字組分割(word splitting)問題。

file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7"
# List of files as argument(s) to a command.
# 即將成為一個指令的參數之檔案列表。

# Add two files to the list, and list all.
# 新增兩個檔案到此列表,並把它全部列出來。
ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_list

echo "-------------------------------------------------------------------------"

# What happens if we escape a couple of spaces?
# 若我們把一堆空格都跳脫掉,會發生什事?
ls -l /usr/X11R6/bin/xsetroot\ /sbin/dump\ $file_list
# Error: the first three files concatenated into a single argument to 'ls -l'
# 錯誤: 前三個檔案路徑全部串聯成單一一個參數給 'ls -l'
#        because the two escaped spaces prevent argument (word) splitting.
#        因為分隔的那兩個空白字元被跳脫掉了,導致阻礙了參數(字組)分割隔開。

The escape also provides a means of writing a multi-line command.

跳脫字元還提供了撰寫一個多行指令的方法。

Normally, each separate line constitutes a different command, but an escape at the end of a line escapes the newline character, and the command sequence continues on to the next line.

正常來說,各別行各自組成一個不同的指令,但若行尾有一個跳脫字元,則會跳脫其後的換行字元,並且指令內容會接續到下一行。

(cd /source/directory && tar cf - . ) | \
(cd /dest/directory && tar xpvf -)
# Repeating Alan Cox's directory tree copy command,
# 照抄 Alan Cox 的目錄複製指令,
# but split into two lines for increased legibility.
# 但分成兩行寫,以提升可讀性。

# As an alternative:
# 另類作法:
tar cf - -C /source/directory . |
tar xpvf - -C /dest/directory
# See note below.
# 請參閱下方注意事項。
# (Thanks, Stéphane Chazelas.)
# (感謝 Stéphane Chazelas 提供上述範例。)

Note: If a script line ends with a |, a pipe character, then a \, an escape, is not strictly necessary.

注意:若腳本裡某行行尾以一個 (|) 豎線(垂直線、管線)字元結束,則不再強制要求追加一個 (\) 反斜線跳脫字元。

It is, however, good programming practice to always escape the end of a line of code that continues to the following line.

但無論如何,隨時在需要接續下一行的該行行尾追加一個跳脫字元是良好的程式設計習慣。

echo "foo
bar"
#foo
#bar

echo

echo 'foo
bar'    # No difference yet.
        # 尚無差異。
#foo
#bar

echo

echo foo\
bar     # Newline escaped.
        # 換行字元已跳脫。
#foobar

echo

echo "foo\
bar"     # Same here, as \ still interpreted as escape within weak quotes.
         # 這個也一樣,因為反斜線 \ 在雙引號(弱引用)裡面仍被解讀為跳脫字元。
#foobar

echo

echo 'foo\
bar'     # Escape character \ taken literally because of strong quoting.
         # 在單引號(強引用)裡面的跳脫字元 \ 則被以字面上的原意解讀。
#foo\
#bar

# Examples suggested by Stéphane Chazelas.
# 感謝 Stéphane Chazelas 提供上述範例。