如何在 Unix shell 中使用特殊字元作為普通字元?
許多問題,例如“如何鍵入雙引號字元 (")?” 正在被問到,我們不想用相同的答案混淆我們的社區(鍵入它,
\"
如果沒有包含在'
s 中,"
如果包含在'
s 中。)所以,問題就在這裡。您不能像普通字元那樣在終端中鍵入特殊字元,例如此命令將失敗:
echo Updates (11)
那麼,如何在終端中輸入這些字元,就好像它們是普通字元一樣?
!#$^&*?[](){}<>~;'"\|<space><tab><newline>
這在很大程度上取決於外殼。查看您的 shell 手冊以獲取詳細資訊。
另請注意,某些字元僅在某些情況下是特殊的。例如,在大多數 shell 中,
*
並且?
僅在列表上下文中是特殊的,在 POSIX 或類似 csh 的 shell 中,~
僅在單詞的開頭或在某些字元(如:
. 相同的=
inzsh
。在某些 shell 中,[
只有在與 a 匹配(有一些限制)時才是特殊的]
。在某些 shell(如
bash
oryash
)中,特殊字元(如空白標記分隔符)也因語言環境而異。引用運算符(以刪除這些字元的特殊含義)在 shell 之間也有很大差異。
伯恩狀貝殼
Bourne-like shell 的摘要(即
sh
自 80 年代以來已知在某個系統或另一個系統上呼叫的 shell):伯恩貝殼
特殊的角色:
"'&|;()^
<>$`、空格、換行符和製表符在不加引號的簡單命令行中是特殊的。#
(早期版本除外)在行首或未加引號的空格、製表符或`&|()^<>;``.{
並且}
唯一的特殊之處在於它們是 shell 關鍵字(因此只有命令位置的單詞)。*?[
作為萬用字元是特殊的,所以只在列表上下文中。在 的情況下[
,它[...]
是萬用字元,要麼[
或]
只需要被引用以消除特殊含義。=
在將其視為賦值運算符的上下文中是特殊的。也就是說,在一個簡單的命令中,對於所有不跟隨參數的單詞(除了 afterset -k
)。報價運算符
\
引用除換行符以外的所有特殊字元(\<newline>
是一種將長邏輯行繼續到下一個物理行的方法,以便刪除該序列)。請注意,反引號在其中增加了額外的複雜性,\
首先用於轉義結束反引號並幫助解析器。在雙引號內,\
只能用於轉義自身,"
和$
(```仍然\<newline>
是續行)。在此處文件中,除了"
.\
是在此處文件中轉義字元的唯一方法。"..."
雙引號轉義除自身之外的所有字元,\
,$
和```.'...'
單引號轉義除自身之外的所有字元。POSIX 外殼
POSIX shell 的行為與 Bourne shell 非常相似,除了:
^
不再是特殊字元~
在某些情況下很特別{
允許是特殊的,所以應該引用。
ksh
像 POSIX 一樣,除了:
{string}
如果字元串包含未引用的,
(或..
在某些情況下和某些版本中),則它是特殊的。- ksh93 有一個額外的特殊引用運算符:
$'...'
具有復雜的規則。bash
該運算符也可以在、zsh
、mksh
FreeBSD 和 busybox中找到(有一些變化)sh
。ksh93
還有一個$"..."
引用運算符,"..."
除了字元串需要本地化(可以配置為翻譯成使用者的語言)外,它的工作方式與此類似。mksh
忽略$
in$"..."
。- 因為
ksh93r
,在互動式 shell 中ksh93
支持 csh 樣式的歷史擴展(預設情況下未啟用),-H
這-o histexpand
使得^
在命令的開頭和!
特殊。!
然後在某些上下文中是特殊的(不是在後面跟著空格或 TAB 時,也不是在此處的文件中),並且不會被雙引號轉義。只有反斜杠(不在雙引號內)和單引號轉義它。
bash
像
ksh93
但是:
- 在單字節字元語言環境中,所有空白(根據語言環境)字元都被視為分隔符(如空格或製表符)。實際上,這意味著您應該引用設置了第 8 位的所有字節,以防它們在某些語言環境中可能是空白字元。
- 在互動式實例中預設啟用 csh 歷史擴展,其註釋與上述 ksh93 相同,只是在較新版本的
bash
,!
有時也不特殊,當後跟 a 時"
。
zsh
像
ksh93
但是:
bash
與csh 歷史擴展相同的註釋=
作為單詞的第一個字元是特殊的(=ls
擴展為/bin/ls
)。{
並且}
還可以在沒有分隔的情況下打開和關閉命令組({echo text}
如 Bourne 之類的作品{ echo text;}
)。- 除了
[
單獨之外,[
即使沒有以 . 結尾,也需要引用]
。extendedglob
啟用該選項後#
,^
和~
是萬用字元。- 帶
braceccl
選項,{non-empty-string}
很特別。$"..."
不支持。- 作為一個特殊的怪癖,在單詞開頭
?
跟隨(甚至引用或擴展)時並不特殊(以允許工作規範)%``%?name
- 一個
rcquotes
選項(預設情況下未啟用)允許''
在單引號 à la中輸入單引號rc
(見下文)。
yash
像
POSIX
除此之外。
- 所有空白字元都被視為分隔符。
- 使用該
brace-expand
選項,實現 zsh 樣式的大括號擴展。對於所有 shell,在某些特殊情況下,引用的工作方式不同。我們已經在這裡提到了文件和反引號,但
[[...]]
在 ksh 和其他一些 shell、POSIX$((...))
、case
構造中也有……另請注意,在擴展(使用雙引號)或應用於此處的文件分隔符時,引用可能會產生其他副作用。它還禁用保留字並影響別名擴展。
概括
在 Bourne-like shell 中
!#$^&*?[(){}<>~;'"
|=`,、SPC、TAB、NEWLINE 和一些設置了第 8 位的字節是或可能是特殊的(至少在某些情況下)。要刪除特殊含義以便按字面意思對待它們,請使用引用。
採用:
'...'
刪除每個字元的特殊含義:printf '%s\n' '\/\/ Those $quoted$ strings are passed literally as single arguments (without the enclosing quotes) to `printf`'
\
僅刪除一個字元的特殊含義:printf '<%s>\n' foo bar\ baz #comment
上面,只有 a 前面的空格字元按
\
字面意思傳遞給printf
. 其他的被 shell 視為標記分隔符。
- 用於
"..."
引用字元,同時仍然允許參數擴展($var
,$#
,${foo#bar}
…),算術擴展($((1+1))
,也在$[1+1]
某些 shell 中)和命令替換($(...)
或舊形式...
。實際上,大多數時候,您確實希望將這些擴展放在裡面任何情況下的雙引號。您可以使用\
within"..."
刪除仍然特殊的字元的特殊含義(但僅限於它們)。- 如果字元串包含
'
字元,您仍然可以使用其餘部分並使用其他'...'
可以引用或或(如果可用)的引用機制:'``"'"``\'``$'\''
echo 'This is "tricky", isn'\''t it?'
- 使用現代
$(...)
形式的命令替換。僅使用舊...
的以與 Bourne shell 兼容,即非常舊的系統,並且僅在變數分配中使用,如不要使用:echo "`echo "foo bar"`"
這不適用於 Bourne shell 或 AT&T 版本的 ksh。或者:
echo "`echo \"foo bar\"`"
這將適用於 Bourne 和 AT&T ksh,但不適用於
yash
(**2020 年編輯:**僅在 2.41 及更早版本中,但已在 2.42 /錯誤報告/送出中更改),但使用:var=`echo "foo bar"`; echo "$var"
這將適用於所有人。
用雙引號將它們可移植地嵌套也是不可能的,所以再次使用變數。還要注意特殊的反斜杠處理:
var=`printf '%s\n' '\\'`
將僅在 內儲存一個反斜杠
$var
,因為在反引號內有額外級別的反斜杠處理(對於\
、和
$(以及
"在引用時除外
yash`)),因此您需要var=`printf '%s\n' '\\\\'`
或者
var=`printf '%s\n' '\\\'
反而。
Csh家族
csh 和 tcsh 具有明顯不同的語法,儘管它們與 Bourne shell 仍有許多共同點,因為它們具有共同的傳統。
特殊的角色:
"'&|;()^
<>$`,空格,換行符和製表符在沒有被引用時在任何地方都是特殊的。#
(csh 是作為註釋前導引入的 shell#
)在腳本開頭或未加引號的空格、製表符或換行符之後是特殊的。*?[
在列表上下文中作為萬用字元是特殊的{non-empty-string}
是特殊的(csh 是引入大括號擴展的外殼)。!
並且^
作為歷史擴展的一部分是特殊的(再次,csh 發明),並且引用規則是特殊的。~
(波浪號擴展也是 csh 的一項發明)在某些情況下是特殊的。報價運算符
它們與 Bourne shell 相同,但行為不同。從語法的角度來看,tcsh 的行為類似於 csh,您會發現許多版本的 csh 都有嚴重的錯誤。獲取最新版本的 tcsh 以獲得大致工作的 csh 版本。
\
轉義除換行符以外的單個字元(與 Bourne shell 相同)。它是唯一可以轉義的引用運算符!
。\<newline>
不會對其進行轉義,而是將其從命令分隔符轉換為標記分隔符(如空格)"..."
轉義除自身$
、、、換行符和`!`.之外的所有字元 與 Bourne shell 不同,您不能使用`\`to escape`$`和
inside"..."
,但您可以使用\
to escape!
或 newline (但不能使用本身,除非在 a!
或 newline 之前)。一個字面!
量是"\!"
和一個字面\!
量是"\\!"
。'...'
轉義除自身!
和換行符以外的所有字元。就像雙引號一樣,!
換行符可以用反斜杠轉義。- 命令替換僅通過
...
語法進行,幾乎不能可靠地使用。- 變數替換的設計也很糟糕並且容易出錯。運算符
$var:q
有助於編寫更可靠的涉及變數的程式碼。概括
如果可以,請遠離 csh。如果你不能使用:
- 單引號引用大多數字元。
!
並且換行符仍然需要一個\
.\
可以轉義大多數字元"..."
可以允許在其中進行一些擴展,但是如果它們嵌入換行符和/或反斜杠字元,那將是非常錯誤的,最好僅使用單引號並$var:q
用於變數擴展。如果要可靠地連接數組的元素,則需要使用循環。
rc
家庭
rc
是plan9
shell 和它的後代一樣es
,並akanga
已被移植到 Unix 和類 unix。這是一個語法更清晰、更好的 shell,如果我們不為向後兼容而堅持使用類似 Bourne 的 shell,每個人都會使用它。
rc
/akanga
特殊的角色
#;&|^$=
’{}()<>`, SPC, TAB 和 NEWLINE 在不被引用時總是特殊的。*?[
是萬用字元運算符。報價運算符
'...'
是唯一的引用運算符。文字'
用''
單引號括起來,如下所示:echo 'it''s so simple isn''t it?'
es
es
可以看作是一個基於rc
.不過,它有一些不同之處。此 Q/A 的一個有趣之處在於
\
它也是一個引用運算符(引用除換行符以外的所有特殊字元),也可用於引入轉義序列,如\n
換行符、\b
反斜杠……魚
fish 是一個相對較新的人(大約 2005 年),主要用於互動式使用,並且與其他 shell 的語法也有很大不同。
特殊的角色
"'\()$%{}^<>;&|
未引用時總是特別的(注意%
(用於 pid 擴展)作為與其他 shell 的顯著區別,```並不特別)#
(註釋)在未加引號的空格、製表符、換行符或;&|^<>
*?
(但不是[...]
)萬用字元運算符報價運算符
\
引用除換行符以外的單個特殊字元,但要注意它還兼作 C 轉義序列 (\n
,\b
…) 介紹器。IOW,\n
不是引用n
而是換行符。"..."
引用除自身之外的所有內容,$
反斜杠和反斜杠可用於轉義這些。\<newline>
是 . 內部的續行(刪除)"..."
。'...'
引用除自身和之外的所有內容\
,您可以使用反斜杠來轉義這些內容。