为什么\ $在反引号内减少到$ [尽管不在$(...)内? [英] Why does \$ reduce to $ inside backquotes [though not inside $(...)]?

查看:98
本文介绍了为什么\ $在反引号内减少到$ [尽管不在$(...)内?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在研究POSIX标准时,我遇到了另一个相当技术性/毫无意义的问题.它状态:

Going over the POSIX standard, I came across another rather technical/pointless question. It states:

在命令替换的反引号格式中,<backslash>应保留其字面意思,除非后面跟有:'$','`'或<backslash>.

Within the backquoted style of command substitution, <backslash> shall retain its literal meaning, except when followed by: '$' , '`' , or <backslash>.

很容易理解为什么'`'和'\'失去其字面含义:嵌套的命令替换要求在命令替换中使用不同的"反引号,从而迫使'\'失去其字面含义.因此,例如,以下不同行为似乎是合理的:

It's easy to see why '`' and '\' lose their literal meanings: nested command substitution demands a "different" backquote inside the command substitution, which in turn forces '\' to lose its literal meaning. So, for instance, the following different behavior seems reasonable:

$ echo $(echo \\\\)
\\
$ echo `echo \\\\`
\

但是'$'呢?也就是说,以下区别有什么意义,或者更具体地讲,可能带来的好处是什么?

But what about '$'? I.e., what's the point or, more concretely, a possible benefit of the following difference?

$ echo $(echo \$\$)
$$
$ echo `echo \$\$`
4735

由于反引号中不排除"$"本身,因此看起来您将一直使用"$"或"\\\ $",但绝不会使用中间字母"\ $".

As '$' by itself is not ruled out inside backquotes, it looks like you would use either '$' or '\\\$' all the time, but never the middle case '\$'.

回顾一下,

$ echo `echo $$` # PID, OK
4735
$ echo `echo \\\$\\\$` # literal "$$", OK
$$
$ echo `echo \$\$` # What's the point?
4735

PS:我知道这个问题是技术性的……我本人一直都在寻求更现代的$(...)替代,但是我仍然很好奇.

PS: I know this question is rather technical... I myself go for the more modern $(...) substitution all the time, but I'm still curious.

推荐答案

基本答案

考虑以下命令,该命令查找安装gcc的基本目录:

gcc_base=$(dirname $(dirname $(which gcc)))

使用$(...)表示法,解析没有问题.这是微不足道的,并且是推荐使用该符号的主要原因之一.使用反引号的等效命令是:

With the $(...) notation, there is no problem with the parsing; it is trivial and is one of the primary reason why the notation is recommended. The equivalent command using back-ticks is:

gcc_base=`dirname \`dirname \\\`which gcc\\\`\``

当shell第一次解析此命令时,它会遇到第一个反引号,并且必须找到匹配的关闭反引号.这是引用的部分生效的时间:

When the shell first parses this command, it encounters the first backtick, and has to find the matching close backtick. That's when the quoted section comes into effect:

在命令替换的后引号样式中,应保留其字面意思,除非后面跟有'$','`'或.

Within the backquoted style of command substitution, shall retain its literal meaning, except when followed by: '$' , '`' , or .

gcc_base=`dirname \`dirname \\\`which gcc\\\`\``
                  ^         ^ ^          ^ ^ ^
                  1         2 3          4 5 6

  1. 反斜杠反引号-特殊规则
  2. 反斜杠-反斜杠-特殊规则
  3. 反斜杠反引号-特殊规则
  4. 反斜杠-反斜杠-特殊规则
  5. 反斜杠反引号-特殊规则
  6. 反斜杠反引号-特殊规则

因此,末尾未转义的反引号标志着最外面的反引号命令的结束.处理该命令的子外壳会看到:

So, the unescaped backtick at the end marks the end of the outermost backtick command. The sub-shell that processes that command sees:

dirname `dirname \`which gcc\``

再次对反斜杠转义符进行特殊处理,并且子子shell看到:

The backslash-back escapes are given the special treatment again, and the sub-sub-shell sees:

dirname `which gcc`

  • sub-sub-sub-shell可以看到which gcc并对其进行评估(例如/usr/gcc/v4.6.1/bin/gcc).
  • 子sub-shell评估dirname /usr/gcc/v4.6.1/bin/gcc并产生/usr/gcc/v4.6.1/bin.
  • 子外壳评估dirname /usr/gcc/v4.6.1/bin并产生/usr/gcc/v4.6.1.
  • shell将/usr/gcc/v4.6.1分配给gcc_base.
    • The sub-sub-sub-shell gets to see which gcc and evaluates it (e.g. /usr/gcc/v4.6.1/bin/gcc).
    • The sub-sub-shell evaluates dirname /usr/gcc/v4.6.1/bin/gcc and produces /usr/gcc/v4.6.1/bin.
    • The sub-shell evaluates dirname /usr/gcc/v4.6.1/bin and produces /usr/gcc/v4.6.1.
    • The shell assigns /usr/gcc/v4.6.1 to gcc_base.
    • 在此示例中,反斜杠后仅跟特殊字符-反斜杠,反引号,美元.例如,一个更复杂的示例在命令中包含\"序列,则该特殊规则将不适用. \"只需简单地不经复制就复制并传递到相关的子shell.

      In this example, the backslashes were only followed by the special characters - backslash, backtick, dollar. A more complex example would have, for example, \" sequences in the command, and then the special rule would not apply; the \" would simply be copied through unchanged and passed to the relevant sub-shell(s).

      例如,假设您有一个名称中带有空格的命令(禁止使用天堂;这表明了原因!),例如totally amazing(两个空格;比单个空格更严格的测试).然后,您可以编写:

      For example, suppose you had a command with a blank in its name (heaven forbid; and this shows why!) such as totally amazing (two blanks; it is a more stringent test than a single blank). Then you could write:

      $ cmd="totally  amazing"
      $ echo "$cmd"
      totally  amazing
      $ which "$cmd"
      /Users/jleffler/bin/totally  amazing
      $ dirname $(which "$cmd")
      usage: dirname path
      $ # Oops!
      $ dirname "$(which \"\$cmd\")"
      "$cmd": not found
      .
      $ # Oops!
      $ dirname "$(which \"$cmd\")"
      "totally: not found
      amazing": not found
      .
      $ dirname "$(eval which \"$cmd\")"
      totally amazing: not found
      .
      $ dirname "$(eval which \"\$cmd\")"
      /Users/jleffler/bin
      $ # Ouch, but at least that worked!
      $ # But how to extend that to the next level?
      $ dirname "$(eval dirname \"\$\(eval which \\\"\\\$cmd\\\"\)\")"
      /Users/jleffler
      $
      

      好的-好的,那是简单"的事情!您是否需要更好的理由来避免在命令名或路径名中出现空格?我也很满意地证明它可以与包含空格的路径名一起正常使用.

      OK - well, that's the "easy" one! Do you need a better reason to avoid spaces in command names or path names? I've also demonstrated to my own satisfaction that it works correctly with pathnames that contain spaces.

      那么,我们可以压缩反引号的学习周期吗?是的...

      So, can we compress the learning cycle for backticks? Yes...

      $ cat x3.sh
      cmd="totally  amazing"
      which "$cmd"
      dirname "`which \"$cmd\"`"
      dirname "`dirname \"\`which \\"\$cmd\\\"\`\"`"
      $ sh -x x3.sh
      + cmd='totally  amazing'
      + which 'totally  amazing'
      /Users/jleffler/bin/totally  amazing
      ++ which 'totally  amazing'
      + dirname '/Users/jleffler/bin/totally  amazing'
      /Users/jleffler/bin
      +++ which 'totally  amazing'
      ++ dirname '/Users/jleffler/bin/totally  amazing'
      + dirname /Users/jleffler/bin
      /Users/jleffler
      $
      

      这仍然是可怕的,令人生畏的,非直觉的转义序列集.它实际上比$(...)表示法的版本短,并且不使用任何eval命令(总是使事情变得复杂).

      That is still a ghastly, daunting, non-intuitive set of escape sequences. It's actually shorter than the version for $(...) notation, and doesn't use any eval commands (which always complicate things).

      这篇关于为什么\ $在反引号内减少到$ [尽管不在$(...)内?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆