类似伯恩的贝壳

类似伯恩的贝壳

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

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

echo Updates (11)

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

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

答案1

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

另请注意,某些字符仅在某些上下文中才特殊。例如,在大多数 shell 中,*and?仅在列表上下文中特殊,在 POSIX 或类似 csh 的 shell 中,~仅在单词开头或后面的某些字符(如 )特殊:。同样适用=zsh.在某些 shell 中,[仅当与 . 匹配(有一些限制)时才特殊]

在某些 shell(如bash或 )中yash,特殊字符(如空白标记分隔符)也会随区域设置而变化。

不同 shell 之间的引用运算符(以删除这些字符的特殊含义)也有很大差异。

类似伯恩的贝壳

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

伯恩外壳

特殊字符:

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

引用运算符

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

POSIX shell

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

ksh

与 POSIX 类似,除了:

  • {string},如果字符串包含不带引号的(或..在某些情况下和某些版本),则为特殊。
  • ksh93 有一个额外的特殊引用运算符:$'...'具有复杂的规则。该运算符也可以在bashzshmkshFreeBSD 和 busybox中找到(有一些变化)sh
  • ksh93还有一个$"..."引用运算符,其工作原理与此类似"...",只是字符串需要本地化(可以配置为将其转换为用户的语言)。mksh忽略$in $"...".
  • 自以来ksh93r,在交互式 shell 中ksh93支持 csh 风格的历史扩展(默认情况下不启用),这使得命令开头变得特殊。那么在某些上下文中是特殊的(不是在后跟空格或 TAB 时,也不是在此处文档中),并且不会用双引号转义。只有反斜杠(不在双引号内,会删除其特殊含义,但不会以其他方式删除)和单引号会转义它。-H-o histexpand^!!\!

bash

喜欢ksh93但是:

  • 在单字节字符语言环境中,所有空白的(根据区域设置)字符被视为分隔符(如空格或制表符)。实际上,这意味着您应该引用设置了第 8 位的所有字节,以防它们在某些语言环境中可能是空白字符。
  • 默认情况下,在交互式实例中启用 csh 历史记录扩展,其注释与上面的 ksh93 相同,只是在较新版本的bash,!有时也并不特殊,当后跟".
  • 与 csh 一样,%在命令的开头用于操作作业。%1将第一个作业置于前台而不是运行%1命令。与%1 &将其放在背景中相同...

zsh

喜欢ksh93但是:

  • 与 csh 历史扩展相同的注释bash,除了反斜杠可用于!在双引号内转义,就像 csh 中一样。
  • =是特殊的,因为单词的第一个字符(=ls扩展为/bin/ls)。
  • %与命令位置中的bash 的注释相同。
  • {并且}还可以在未分隔时打开和关闭命令组({echo text}如 Bourne 的作品中{ echo text;})。
  • 除了[单独的情况外,[即使不以 . 结束,也需要引用]
  • 启用该extendedglob选项后,#^~是通配运算符。
  • 有了这个braceccl选项,{non-empty-string}就特别了。
  • $"..."不支持。
  • 作为一个特殊的怪癖,当在单词开头?跟随 a (甚至引用或扩展)时并不特殊(以允许工作规范)%%?name
  • 选项rcquotes(默认情况下未启用)允许''在单引号内输入单引号rc(见下文)。

yash

除了POSIX那个之外。

  • 所有空白字符都被视为分隔符。
  • 使用该brace-expand选项,实现 zsh 风格的大括号扩展。
  • 与命令位置中的 bash 和 zsh 的注释相同%(POSIX 模式下除外)。

对于所有 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。其他的被 shell 视为标记分隔符。

  • 用于"..."引用字符,同时仍然允许参数扩展($var, $#, ${foo#bar}...)、算术扩展($((1+1)),也在$[1+1]某些 shell 中)和命令替换$(...)或者旧的形式`...`。实际上,大多数时候,你这样做无论如何都想将这些扩展放在双引号内。您可以使用\inside"..."删除仍然特殊的字符(但仅限于它们)的特殊含义。

  • 如果字符串包含'字符,您仍然可以使用'...'其余的字符,并使用其他引用机制,可以引用'"'"or \'or (如果可用)$'\''

    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 和 tcsh 具有显着不同的语法,但与 Bourne shell 仍然有很多共同点,因为它们具有共同的传统。

特殊字符:

  • "'&|;()^`<>$、空格、换行符和制表符在不加引号时在任何地方都是特殊的。
  • #(csh 是作为注释引导符引入的 shell #)在脚本的开头或在未加引号的空格、制表符或换行符之后是特殊的。
  • *?[作为通配符是特殊的,所以在列表上下文中
  • {anything}是特殊的,除了独立的特殊情况{}(csh 是引入大括号扩展的 shell)。
  • !^作为历史扩展的一部分是特殊的(同样是 csh 的发明),并且引用规则是特殊的。
  • ~(波形符扩展也是 csh 的发明)在某些情况下是特殊的。
  • 与 bash、zsh、yash 一样,%命令位置用于操作作业(又是 csh 的发明)。

引用运算符

它们与 Bourne shell 相同,但行为不同。从语法的角度来看,tcsh 的行为类似于 csh,您会发现许多版本的 csh 都有严重的错误。获取最新版本的 tcsh 以获取大致可以工作的 csh 版本。

  • \转义除换行符之外的单个字符(与 Bourne shell 相同)。它是唯一可以转义的引用运算符!\<newline>不会转义它,而是将其从命令分隔符转换为标记分隔符(如空格)
  • "..."转义除自身之外的所有字符、$`、 换行符和!。与 Bourne shell 相反,您不能使用\escape$`inside "...",但可以使用\escape!或换行符(但不能使用其本身,除非在 a!或换行符之前)。文字!"\!",文字\!"\\!"
  • '...' 转义除自身!和换行符之外的所有字符。与双引号一样,!换行符可以用反斜杠转义。
  • 命令替换只能通过语法进行`...`,很难可靠地使用。
  • 变量替换的设计也相当糟糕并且容易出错。运算符$var:q有助于编写涉及变量的更可靠的代码。

概括

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

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

rc家庭

rcplan9外壳。 plan9 代码现已作为 FLOSS 发布,其用户空间软件包括rc已移植到 Linux。 Byron Rakitzis 也在 90 年代初编写了 for Unix的克隆版本rc,并从中派生出esakanga

这是一种具有更清晰、更好语法的 shell,如果我们不为了向后兼容而使用类似 Bourne 的 shell,那么每个人都会使用它。

rc/akanga

特殊字符

  • #;&|^$=`'{}()<>、SPC、TAB 和 NEWLINE 在不加引号时始终是特殊的。
  • *?[是通配符运算符。

引用运算符

'...'是唯一的引用运算符。文字'用单引号括起来,''如下所示:

echo 'it''s so simple isn''t it?'

es

es可以看作是实验性的外壳基于rc.

但它有一些差异。本问答的有趣之处在于它\也是一个引用运算符(引用除换行符之外的所有特殊字符),并且还可以用于引入转义序列,例如\n换行符、\b反斜杠......

Fish 是一个相对较新的产品(大约 2005 年),主要用于交互式使用,并且与其他 shell 具有显着不同的语法。

特殊字符

  • "'\()$%{}^<>;&|不加引号时总是特殊的(请注意%(对于 pid 扩展)与其他 shell 有显着差异,并且`并不特殊)
  • #(注释)在未加引号的空格、制表符、换行符或;&|^<>
  • *?(但不是[...])通配运算符

引用运算符

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

答案2

1. 逃亡

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

$ 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

相关内容