如何在 Unix shell 中将特殊字符用作普通字符?

EKo*_*ons 14 shell special-characters quoting

许多问题,例如“如何键入双引号字符 (")?” 正在被问到,我们不想用相同的答案来扰乱我们的社区(输入时\"好像不包含在's 中,"如果包含在's 中。)所以,问题就在这里。

您不能像普通字符那样在终端中输入特殊字符,例如此命令将失败:

echo Updates (11)
Run Code Online (Sandbox Code Playgroud)

那么,如何在终端中输入这些字符,就像它们是普通字符一样?

echo Updates (11)
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 32

这在很大程度上取决于外壳。有关详细信息,请查看您的 shell 手册。

另请注意,某些字符仅在某些上下文中是特殊的。例如,在大多数 shell 中,*并且?仅在列表上下文中是特殊的,在 POSIX 或类似 csh 的 shell 中,~仅在单词的开头或某些字符(如:. 同为=in zsh。在某些 shell 中,[只有在与].

在某些 shell 中,如bashyash,特殊字符(如空白标记分隔符)也因区域设置而异。

引号操作符(删除这些字符的特殊含义)在不同的 shell 之间也有很大差异。

类似伯恩的贝壳

类似 Bourne 的 shell(即sh自 80 年代以来已知在某些系统或其他系统上调用的 shell)的摘要:

伯恩壳

特殊的角色:

  • "'&|;()^`<>$、空格、换行符和制表符在不带引号的简单命令行中是特殊的。
  • #(早期版本除外)在行首或未加引号的空格、制表符或&|()^<>;`.
  • {并且}唯一的特殊之处在于它们是 shell 关键字(因此只有在命令位置的单词)。
  • *?[作为通配符是特殊的,所以只在列表上下文中。在 的情况下[,它[...]是通配符,要么[]只需要引用以删除特殊含义。
  • =在将其视为赋值运算符的上下文中是特殊的。也就是说,在一个简单的命令中,对于所有不跟在参数后面的词(除了之后set -k)。

引用运算符

  • \引用除换行符之外的所有特殊字符(\<newline>是一种将长逻辑行延续到下一个物理行的方法,以便删除该序列)。请注意,反引号会增加额外的复杂性,因为它们\首先用于转义结束反引号并帮助解析器。在双引号内,\只能用于转义自身,",$`(\<newline>仍然是一个续行)。在 here-document 中,除了". \是对此处文档中的字符进行转义的唯一方法。
  • "..."双引号转义除自身、\$和 之外的所有字符`
  • '...' 单引号转义除自身之外的所有字符。

POSIX 外壳

POSIX shell 的行为与 Bourne shell 大致相似,不同之处在于:

ksh

像 POSIX 一样,除了:

  • {string}如果 string 包含未加引号的,(或..在某些情况下和某些版本中)则是特殊的。
  • ksh93 有一个额外的特殊引用运算符:$'...'复杂规则。在bashzshmkshFreeBSD 和 busybox 中也可以找到该运算符(有一些变化)sh
  • ksh93也有一个$"..."引用操作符,"..."除了字符串需要本地化(可以配置为翻译成用户的语言)。mksh忽略$in $"..."
  • 因为ksh93r,在交互式 shell 中ksh93使用-H/支持 csh 风格的历史扩展(默认情况下不启用),-o histexpand这使得^命令的开头和!特殊。!然后在某些上下文中是特殊的(后面不是空格或制表符,也不是在此处的文档中)并且不会被双引号转义。只有反斜杠(不在双引号内)和单引号转义它。

bash

喜欢ksh93但是:

  • 在单字节字符语言环境中,所有空白(根据语言环境)字符都被视为分隔符(如空格或制表符)。实际上,这意味着您应该引用第 8 位设置的所有字节,以防它们在某些语言环境中可能是空白字符。
  • csh 历史扩展在交互式实例中默认启用,与上面 ksh93 上的注释相同,除了在较新版本的bash,!有时也不特别,当后跟".

zsh

喜欢ksh93但是:

  • bashcsh 历史扩展相同的注意事项
  • =作为单词的第一个字符(=ls扩展为/bin/ls)是特殊的。
  • {并且}还可以在未分隔时打开和关闭命令组({echo text}如 Bourne's 之类的作品{ echo text;})。
  • 除了[单独之外,[即使没有用].
  • extendedglob启用该选项后#^~是通配符。
  • braceccl选项,{non-empty-string}很特别。
  • $"..." 不支持。
  • 作为一个特殊的怪癖,在单词开头?跟随 a %(甚至引用或扩展)时并不特殊(以允许%?name工作规范)
  • 一个rcquotes选项(默认情况下未启用)允许在单引号''内输入单引号 à la rc(见下文)。

yash

就像POSIX不同的是。

  • 所有空白字符都被视为分隔符。
  • 使用该brace-expand选项,实现 zsh 样式的大括号扩展。

对于所有 shell,在某些特殊上下文中,引用的工作方式有所不同。我们已经在这里提到了文档和反引号,但[[...]]在 ksh 和其他一些 shell、POSIX $((...))case构造中也有...

另请注意,当涉及扩展(使用双引号)或应用于此处的文档分隔符时,引用可能会产生其他副作用。它还禁用保留字并影响别名扩展。

概括

在类似 Bourne 的 shell 中,!#$^&*?[(){}<>~;'"`|=、SPC、TAB、NEWLINE 和一些设置了第 8 位的字节是或可能是特殊的(至少在某些情况下)。

要删除特殊含义以便按字面意思对待它们,请使用引用。

用:

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 相反,您不能使用\转义$`内部"...",但您可以使用\转义!或换行符(但不能使用它本身,除非在 a!或换行符之前)。文字!"\!"和文字\!"\\!"
  • '...' 转义除自身!和换行符以外的所有字符。就像双引号一样,!换行符可以用反斜杠转义。
  • 命令替换仅通过`...`语法进行,很难可靠地使用。
  • 变量替换的设计也很糟糕,容易出错。一个$var:q运营商可以帮助编写更可靠的代码包含变量。

概括

如果可以,请远离 csh。如果您不能使用:

  • 单引号引用大多数字符。!和换行符仍然需要一个\.
  • \ 可以转义大多数字符
  • "..."可以允许在其中进行一些扩展,但是如果它们嵌入换行符和/或反斜杠字符,那就很麻烦了,最好只使用单引号并$var:q用于变量扩展。如果要可靠地连接数组元素,则需要使用循环。

rc 家庭

rcplan9shell 及其后代esakanga并已移植到 Unix 和类 Unix 系统。这是一个具有更清晰和更好语法的外壳,如果我们不坚持使用类似 Bourne 的外壳来实现向后兼容性,那么每个人都会使用这种外壳。

rc/akanga

特殊的角色

  • #;&|^$=`'{}()<>, SPC, TAB 和 NEWLINE 在不引用时总是特殊的。
  • *?[ 是通配符。

引用运算符

'...'是唯一的引用运算符。一个litteral'写有''单引号作为内:

echo 'it''s so simple isn''t it?'
Run Code Online (Sandbox Code Playgroud)

es

es可以被看作是一个实验基于壳rc

虽然它有一些差异。这个 Q/A 的一个有趣之处在于\它也是一个引用运算符(它引用除换行符之外的所有特殊字符),也可用于引入转义序列,如\n换行符、\b反斜杠......

fish 是一个相对较新的人(大约 2005 年),主要用于交互式使用,并且与其他 shell 的语法也有很大不同。

特殊的角色

  • "'\()$%{}^<>;&|不引用时总是特殊的(注意%(对于 pid 扩展)作为与其他 shell 的显着区别,`并不特殊)
  • # (comment) 跟随未加引号的空格、制表符、换行符或 ;&|^<>
  • *?(但不是[...])通配符

引用运算符

  • \引用除换行符之外的单个特殊字符,但要注意它也可以作为 C 转义序列 ( \n, \b...) 介绍人使用。IOW,\n不是引用n而是换行符。
  • "..."引用除自身以外的所有内容,$反斜杠和反斜杠可用于转义这些内容。\<newline>是 内的续行(已删除)"..."
  • '...'引用除自身和之外的所有内容\,您可以使用反斜杠来转义它们。


EKo*_*ons 5

1. 逃亡

使用 a 转义所有这些字符\,如下所示(不适用于换行符/回车符):

$ echo Use a \"\\\" symbol to escape characters.
Use a "\" symbol to escape characters.
Run Code Online (Sandbox Code Playgroud)

2.双引号

将整个文本括在"s 中,如下所示:

$ var=variables;echo "Enclose text in \"s. You can also use $var in them. `echo Surprise!!!`"
Enclose text in "s. You can also use variables in them. Surprise!!!
Run Code Online (Sandbox Code Playgroud)

3. 单引号

与双引号相同,但没有特殊标记。

$ proof=proveit;echo 'This should not read "proveit": $proof'
This should not read "proveit": $proof
Run Code Online (Sandbox Code Playgroud)