将 \* 作为参数传递给参数

Passing \* as a parameter for a parameter

使用 ksh。尝试重用当前脚本而不修改它,基本上可以归结为这样的事情:

 `expr 5  `

如何将乘法命令 (*) 作为参数 $1 传递?

我首先尝试使用“*”,甚至是 \*,但没有用。 我尝试了多个转义反斜杠和引号组合,但我认为我做错了。

不修改脚本,我觉得做不到:

  • 调用时,您可以将文字*作为'*'"*"或[=13=传递](任何人都可以):这将 最初 保护 * 免受 shell 扩展(由 shell 解释)。

  • 被调用者(脚本)随后将接收文字 *(如 </code>),但由于 <em>unquoted</em> 在脚本中使用 <code> * 将不可避免地受到文件名扩展(globbing)的影响,并将扩展到所有当前文件夹中的(非隐藏)文件名,打破了 expr 命令。

  • 尝试添加额外的转义层 - 例如 "'*'"\\* - 将不起作用,因为额外的转义将成为参数的 embedded, literal 部分 - 目标脚本将看到 literal '*'\* 和将它 按原样 传递给 expr,这将失败,因为两者都不是有效的运算符。


这是一个解决方法

  • 更改为 目录。
    • 默认情况下,如果没有匹配的文件名,ksh 将 return 任何 glob(模式)原样。因此,*(或任何其他 glob)将在 目录中保持不变,因为没有任何匹配项(感谢,@Peter Cordes)。
    • 对于调用脚本/交互shell,您可以通过运行set -f完全禁用globbing,但请注意,这不会影响 调用的 脚本。
  • 现在可以安全地使用 '*'(或任何其他 glob)调用您的脚本,因为它会被简单地传递;例如,script '*' 2,现在将按预期产生 10
    • 如果您从 调用的 shell 和 脚本的 shell 都是 ksh(或 bash)默认配置,你甚至可以摆脱 script * 2;即,您可以不完全引用 *

Glob 扩展发生得非常晚,在参数扩展和分词(按此顺序)之后。引号删除不会发生在早期扩展的结果上,只是在命令行上开始。这排除了通过使用额外的引号层来传递带引号的 \* 或类似的(参见 mklement0 的回答)。

它还排除了传入 space-padded *:分词删除了路径名(glob)扩展之前的 spaces,所以它最终仍然扩展 * 到目录中的所有文件名。

foo(){ printf '"%s"\n' "$@"; set -x; expr 5  ; set +x; }
$ foo ' * ' 4
" * "
"4"
+ expr 5 ...contents of my directory... 4
expr: syntax error
+ set +x

您应该在有人使用以危险方式破坏它的 arg 而不仅仅是不方便的 arg 运行它之前修复这个有问题的脚本。


如果您不需要支持与 expr 完全相同的运算符,您可能希望使用算术扩展来实现,而无需 运行 外部命令:

result=$((5  ))   # arithmetic expansion for the right-hand side
# or
((result=5 "" ""))  # whole command is an arithmetic expression.

参数周围的双引号在算术表达式中是可选的,但您不需要在算术扩展中使用它们(在 bash 中。显然这在 ksh 中有效)。

通常情况下,总是引用并不是一个坏习惯,除非你特别想要分词和 glob 扩展。