这很大程度上取决于外壳。有关详细信息,请查阅您的Shell手册。
另请注意,某些字符仅在某些情况下是特殊的。例如,在大多数外壳程序中,*
并且?
仅在列表上下文中是特殊的,在POSIX或类似csh的外壳程序中,~
仅在单词开头或某些字符(如之后)才是特殊的:
。同为=
在zsh
。在某些shell中,[
仅当与(有一些限制)匹配时才是特殊的]
。
在某些shell中,例如bash
或yash
,空白字符定界符之类的特殊字符也会随语言环境而变化。
外壳之间的引用运算符(以消除那些字符的特殊含义)也有很大不同。
伯恩样贝壳
Bourne类shell(即sh
自80年代以来已知在某些系统或其他系统上被调用的shell)的摘要:
伯恩壳
特殊的角色:
"\'&|;()^`<>$
,空格,换行符和制表符在未引用时在简单命令行中是特殊的。
#
(早期版本除外)在一行的开头或未加引号的空格,制表符或时是特殊的&|()^<>;`
。
{
并且}
只有特殊之处在于它们是shell关键字(因此仅命令位置的单词)。
*?[
作为全局运算符是特殊的,因此仅在列表上下文中。在的情况下[
,[...]
就是globlob运算符,[
或者]
只需要用引号将其删除即可。
=
在将其视为赋值运算符的上下文中,这是特殊的。也就是说,在一个简单的命令中,对于所有不跟在参数后面的单词(除外set -k
)。
报价运营商
\
引用除换行符以外的所有特殊字符(这\<newline>
是一种将较长的逻辑行延续到下一条物理行,从而删除序列的方法)。请注意,反引号会增加它们内部的复杂性,\
它首先用于逃避结束反引号并帮助解析器。在双引号内,\
只能用于转义自身"
,$
并且,`
(\<newline>
仍然是行继续)。在here文档中,除了"
。\
是在此处文档中转义字符的唯一方法。
"..."
双引号转义所有字符,但本身\
,$
和`
。
'...'
单引号会转义所有字符,但会转义。
POSIX外壳
POSIX外壳的行为与Bourne外壳大致相同,除了:
ksh
类似于POSIX,不同之处在于:
{string}
如果string包含无引号,
(或..
在某些情况下以及某些版本),则为特殊字符。
- ksh93还有一个特殊的引号运算符:
$'...'
具有复杂的规则。该操作员还发现(有一些变化)中bash
,zsh
,mksh
和FreeBSD和busybox的sh
。
ksh93
还具有一个$"..."
引用运算符,其作用类似于"..."
字符串,但该字符串要进行本地化(可以配置为将其转换为用户的语言)。mksh
忽略$
in $"..."
。
bash
喜欢ksh93
但是:
- 在单字节字符语言环境中,所有空白(根据语言环境)字符都被视为定界符(例如空格或制表符)。实际上,这意味着您应该对所有设置了第8位的字节加引号,以防它们在某些区域设置中可能是空白字符。
- 当像在交互式实例中一样启用csh历史扩展时,
!
在某些情况下它是特殊的,并且双引号并不总是将其转义。并且^
在命令开始时是特殊的。
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的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
。外壳将其他变量视为令牌定界符。
- 使用
"..."
引用字符,同时仍允许参数扩展($var
,$#
,${foo#bar}
...),算术扩展($((1+1))
也$[1+1]
有些壳)和命令替换($(...)
或旧的形式`...`
。其实,大多数的时候,你都希望把这些扩展内部在任何情况下,双引号,你可以使用\
内"..."
删除仍在特殊字符的特殊含义(但只有)。
如果字符串包含'
字符,'...'
则其余部分仍可以使用,也可以使用其他可以引用'
like "'"
或\'
or的引用机制$'\''
:
echo 'This is "tricky", isn'\''t it?'
使用现代$(...)
形式的命令替换。仅将旧`...`
版本与Bourne shell兼容,即与非常旧的系统兼容,并且仅在变量分配中使用,如不使用:
echo "`echo "foo bar"`"
不适用于Bourne Shell或ksh的AT&T版本。要么:
echo "`echo \"foo bar\"`"
可以与Bourne和AT&T ksh一起yash
使用,但不适用于,但可以使用:
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相反,您不能使用\
Escape $
和`
inside "..."
,而是可以使用\
Escape !
或换行符(但本身不能使用,除非在a !
或换行符之前)。文字!
是"\!"
,文字\!
是"\\!"
。
'...'
转义除自身!
和换行符以外的所有字符。就像双引号一样,!
换行符可以用反斜杠转义。
- 命令替换仅通过
`...`
语法进行,几乎无法可靠地使用。
- 变量替换的设计也很糟糕,容易出错。一个
$var:q
运营商可以帮助编写更可靠的代码包含变量。
摘要
如果可以,请远离csh。如果您不能使用:
- 单引号引用大多数字符。
!
和换行仍然需要一个\
。
\
可以逃脱大多数角色
"..."
可以允许在其中进行一些扩展,但是如果它们嵌入换行符和/或反斜杠字符,则这是相当麻烦的,最好是仅使用单引号并将其$var:q
用于变量扩展。如果要可靠地连接数组的元素,则需要使用循环。
rc
家庭
rc
是plan9
shell,并且像它的后代一样es
,akanga
已经移植到Unix和unix-like。这是一种具有更简洁更好的语法的外壳,如果我们不使用类似于Bourne的外壳以实现向后兼容性,那么每个人都将使用该外壳。
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>
是()内的行的延续"..."
。
'...'
引用除本身和以外的所有内容\
,您可以使用反斜杠将其转义。
=
,@
并且%
是在某些情况下一些炮弹特殊。