echo \\* - bash 反斜杠转义行为,是否向后求值?

echo \\* - bash 反斜杠转义行为,是否向后求值?

所以在 bash 中,当我这样做时

echo \*
*

这似乎是正确的,因为 * 被转义并按字面​​意思理解。

但我无法理解,当我这样做时

echo \\*
\*

我认为第一个反斜杠转义了第二个反斜杠,因此两个反斜杠“\\”会给我一个字面上的“\”。后面的 * 带有其特殊含义。我期待着:

echo \\*
\file1 file2 file3

答案摘要:由于 \ 是按字面意思理解的,echo \*因此其行为与 一样echo a*,它将查找以文字“a”开头的任何文件。

跟进问题,如果我想打印出来完全一样

\file1 file2 file3

我应该使用什么命令?例如,如下所示,但我不需要空间

echo \\ * 
\ file1 file2 file3

答案1

如果当前目录中没有名称以反斜杠开头的文件,这是预期的行为。重击扩展*以匹配任何现有文件名,但是:

如果模式与任何现有文件名或路径名都不匹配,则模式字符串应保持不变。

因为没有以 开头的文件名\,所以该模式保持原样并被echo赋予参数\*。这种行为常常令人困惑,而其他一些 shell(例如zsh)则没有这种行为。你可以在 Bash 中使用以下命令更改它shopt -o failglob,然后它会给出一个错误,zsh并帮助您诊断问题而不是行为不当。

*和模式字符?可以出现在单词中的任何位置,并且前后字符按字面意思匹配。这就是为什么echo \\*andecho \\ *给出如此不同的输出:第一个匹配以 开头的任何内容\(并失败),第二个输出 a \,然后是所有文件名。


安全地获得所需输出的最直接方法可能是使用打印函数:

printf '\\'; printf "%s " *

echo *-在任何情况下,如果其中包含不寻常的文件名,都是不安全的\

答案2

尝试这个:

printf "\\%s" "$(echo *)"

解释:

  • printf接受一个格式参数和零个或多个替换到格式字符串中的参数
  • \\格式中的含义与中相同echo \\
  • %s表示采用下一个参数并将其代入结果中
  • "$(echo *)"意思是:执行echo *,并将结果放入 的单个参数中printf;由于printf工作原理,它必须放入一个参数中

答案3

尝试...

set file*
printf %s\  "\\$@"

它将在数组的头部添加一个反斜杠 - 所以只有第一个元素。你也可以对结尾做同样的事情。您可以将它们全部用反斜杠分开,\\例如:

printf \\%s file*

...或者...

set file*; IFS=\\; printf %s\\n "$*"

答案4

我相信问题后半部分(“我应该使用什么命令?”)的所有其他答案都是错误的,即使只是在技术上或在边缘情况下。我相信这解决了其他答案中的问题:

(set -- *; echo "\\$*")

并且(FWIW)所有写入都是在单个命令中完成的
(与printf '\\'; printf "%s " *; echo)不同。

  • 使用子 shell 可以避免在外部作用域/上下文中设置/更改位置参数。
  • 天真地,set *将位置参数($1$2$3等)设置为当前目录中的文件名称。 (文件名开头为.(点)是否包含在内,取决于是否dotglob设置了该选项。)
  • set *如果存在名称开头的文件,则可能会失败-(破折号)(它是*列表中的第一个文件)。  set -- *处理这个; --说“这之后的所有内容都是参数,而不是选项/标志。”
  • $*$1 $2 $3 …是位置参数 ( ) 的列表,参数之间用空格分隔。原因\\\在行的开头输出,就像echo \\ *(问题中的示例命令)一样,但它不会干扰后续$*.
  • $*是位置参数列表 ( $1 $2 $3 …), 参数由第一个字符分隔$IFS。如果 的第一个字符$IFS可能不是空格,请执行
(set -- *; IFS=" "; echo "\\$*")

稍微详细一点的选项包括

(set -- *; printf "%s\n" "\\$*")

(set -- *; printf "\\%s\n" "$*")

echo在即使没有选项也可能解释参数字符串中的反斜杠的环境中,这些更安全-e

再次,IFS=" ";如果 的第一个字符$IFS可能不是空格,请添加。

相关内容