如何使用特殊字符作为普通字符?


13

许多问题,例如“如何键入双引号char(“)?” 被问到,而我们不想以相同的答案使我们的社区混乱(输入时,\"如果没有用's "括起来,则键入它,如果没有用s 括起来'。)因此,问题就在这里。

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

echo Updates (11)

那么,如何在终端中像正常字符一样键入这些字符?

!#$^&*?[](){}<>~;'"\|<space><tab><newline>

我没有Unix shell,我不知道回车符在哪里特别。=@并且%是在某些情况下一些炮弹特殊。
斯特凡Chazelas

@StéphaneChazelas嗯...回车(^M)的行为就像^J对我的换行()(Ubuntu 14.04,sh)。
EKons,2016年

不,您的终端驱动程序^M^J在输入时转换为,但^M不是外壳程序专用的,不需要加引号。键入echo ^V^M | hd,您将看到0d字符(以及回声后面的0a)。
斯特凡Chazelas

@StéphaneChazelas嗯...我不知道是什么hdxxd作为十六进制查看器也许更好。
EKons,2016年

任何。如果没有,请使用POSIX od -tx1sed -n lvim的xxd hd。有些系统还具有cat -vtecat -A
斯特凡Chazelas

Answers:


27

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

另请注意,某些字符仅在某些情况下是特殊的。例如,在大多数外壳程序中,*并且?仅在列表上下文中是特殊的,在POSIX或类似csh的外壳程序中,~仅在单词开头或某些字符(如之后)才是特殊的:。同为=zsh。在某些shell中,[仅当与(有一些限制)匹配时才是特殊的]

在某些shell中,例如bashyash,空白字符定界符之类的特殊字符也会随语言环境而变化。

外壳之间的引用运算符(以消除那些字符的特殊含义)也有很大不同。

伯恩样贝壳

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

伯恩壳

特殊的角色:

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

报价运营商

  • \引用除换行符以外的所有特殊字符(这\<newline>是一种将较长的逻辑行延续到下一条物理行,从而删除序列的方法)。请注意,反引号会增加它们内部的复杂性,\它首先用于逃避结束反引号并帮助解析器。在双引号内,\只能用于转义自身"$并且,`\<newline>仍然是行继续)。在here文档中,除了"\是在此处文档中转义字符的唯一方法。
  • "..."双引号转义所有字符,但本身\$`
  • '...' 单引号会转义所有字符,但会转义。

POSIX外壳

POSIX外壳的行为与Bourne外壳大致相同,除了:

ksh

类似于POSIX,不同之处在于:

  • {string}如果string包含无引号,(或..在某些情况下以及某些版本),则为特殊字符。
  • ksh93还有一个特殊的引号运算符:$'...'具有复杂的规则。该操作员还发现(有一些变化)中bashzshmksh和FreeBSD和busybox的sh
  • ksh93还具有一个$"..."引用运算符,其作用类似于"..."字符串,但该字符串要进行本地化(可以配置为将其转换为用户的语言)。mksh忽略$in $"..."

bash

喜欢ksh93但是:

  • 在单字节字符语言环境中,所有空白(根据语言环境)字符都被视为定界符(例如空格或制表符)。实际上,这意味着您应该对所有设置了第8位的字节加引号,以防它们在某些区域设置中可能是空白字符。
  • 当像在交互式实例中一样启用csh历史扩展时,!在某些情况下它是特殊的,并且双引号并不总是将其转义。并且^在命令开始时是特殊的。

zsh

喜欢ksh93但是:

  • bashcsh历史记录扩展相同的注释
  • =作为单词的第一个字符(=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 家庭

rcplan9shell,并且像它的后代一样esakanga已经移植到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>是()内的行的延续"..."
  • '...'引用除本身和以外的所有内容\,您可以使用反斜杠将其转义。

我只包括了所有情况下的特殊代码(这样的c行为与,相同\cc不会c: command not found在STDERR上输出,等等),我在sh这里说的是。另外,请记住,这是一个“清理”问题,即此处包含所有此类字符,因此不必询问19个以上的问题。由于发生这样的事件,即针对不同的此类字符询问了不同的问题,因此发布了该问题,我们当然希望在此进行清理!
EKons,2016年

嗯,?[是遍历运算符,但并不是在所有情况下都特别,而是*似乎是这样,因为当前目录的内容echo *不好用echo(不转义任何内容)。echo ?回显文字?并回显echo [文字[。另外,]也是一个阻塞的obob。
EKons,2016年

1
@ΈρικΚωωσταντόπουλος,*随着全局扩展到所有非隐藏文件,?非隐藏单字符文件,[a-z]名称是a和z之间的单个字符的文件,依此类推。当它们与任何文件都不匹配时(例如您在的情况下?),根据外壳程序,您会遇到不匹配错误,或者模式会扩展为自身。在任何情况下,即使在外壳他们扩大自己,他们需要报价在情况下,他们可以匹配的文件。
斯特凡Chazelas

但是,作为一个整体,它*仍然可以扩展为某种东西。
EKons,2016年

@ΈρικΚωωσταντόπουλος *就像?,如果不匹配(对于*单独的情况,那是当前目录中只有隐藏文件,因为a*那是没有名称以a... 开头的文件),它会扩展为本身(最类似Bourne外壳),或引起了不匹配的误差(cshtcshfish(警告), ,zshbash -O failglob早期的Unix shell)中(或什么也不扩展一些贝壳,或者如果nullglob选项,将会有另一种模式用于扩展为csh,tcsh,zsh -o cshnullglob,早期的unix shell中的内容)。
斯特凡Chazelas

4

1.逃生

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

$ echo Use a \"\\\" symbol to escape characters.
Use a "\" symbol to escape characters.

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!!!

3.单引号

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

$ proof=proveit;echo 'This should not read "proveit": $proof'
This should not read "proveit": $proof

1
您是在描述fishshell 的行为,而不是像Bourne这样的shell,因为单引号引用了每个字符(反斜杠在内并不特殊'...')。需要注意的是在fish%也是一个特殊字符。
斯特凡Chazelas

@StéphaneChazelas我不知道如何fish工作,但我的经验是,在shecho '\\'回声\ echo '\''回声'
EKons,2016年

1
echo '\\'输出\,因为您echo扩展了ANSI C转义序列(为此echo需要某些实现echo -e '\\')。printf '%s\n' '\\'输出\\。
斯特凡Chazelas

请注意,sh它不能识别特定的外壳,存在并且有很多不同的且通常不兼容的外壳称为sh
斯特凡Chazelas

@StéphaneChazelas好的,我现在将其更改。顺便说一句,\'在单引号字符序列中是否有特殊标记?
EKons,2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.