gpt4 book ai didi

从命令行传递字符串时的 Bash 怪癖

转载 作者:行者123 更新时间:2023-11-29 09:14:35 24 4
gpt4 key购买 nike

这是我为演示古怪行为而创建的示例。我希望 bash 按原样传递引用的命令行参数。

john@doe:~/tmp$ cat script.sh 
#! /bin/bash
set -o xtrace
$1 sleep 3
john@doe:~/tmp$ ./script.sh "echo"
+ echo sleep 3
sleep 3
john@doe:~/tmp$ ./script.sh "echo -n"
+ echo -n sleep 3
sleep 3john@doe:~/tmp$

但有时 bash 会编辑我的字符串参数,并在符号周围添加刻度喜欢 ;或者 &&

john@doe:~/tmp$ ./script.sh "echo hello ;"
+ echo hello ';' sleep 3
hello ; sleep 3
john@doe:~/tmp$ ./script.sh "echo hello && "
+ echo hello '&&' sleep 3
hello && sleep 3

什么是 bash 规则以及如何规避它?非常感谢:)

最佳答案

手册中概述了该规则:Section Shell Operation .

你会读到:

The following is a brief description of the shell’s operation when it reads and executes a command. Basically, the shell does the following:

  1. Reads its input from a file (see Shell Scripts), from a string supplied as an argument to the -c invocation option (see Invoking Bash), or from the user’s terminal.
  2. Breaks the input into words and operators, obeying the quoting rules described in Quoting. These tokens are separated by metacharacters. Alias expansion is performed by this step (see Aliases).
  3. Parses the tokens into simple and compound commands (see Shell Commands).
  4. Performs the various shell expansions (see Shell Expansions), breaking the expanded tokens into lists of filenames (see Filename Expansion) and commands and arguments.
  5. Performs any necessary redirections (see Redirections) and removes the redirection operators and their operands from the argument list.
  6. Executes the command (see Executing Commands).
  7. Optionally waits for the command to complete and collects its exit status (see Exit Status).

所以,有了你的脚本:

#! /bin/bash

$1 sleep 3

当你执行 ./script "echo hello ;" 时会发生什么?

  1. Bash 读取您的脚本。
  2. 它将输入分解为单词和运算符。请注意,此时 Bash 看不到参数 echo hello ; 中的控制运算符 ;。此时,它只看到三个标记 $1sleep3
  3. 它将标记解析为简单和复合的命令。目前还没有简单或复合命令。
  4. 它执行 shell 和文件名扩展:此时,您的 token $1 被扩展为 echohello(并不是说这里的分号就变成了参数,不能理解为控制运算符,因为控制运算符的扫描已经在第2步完成,不再执行)。
  5. 这里没有要执行的重定向。
  6. Bash 现在执行命令:它看到带有参数 hello;sleep 的命令 echo3。所以它愉快地回应 hello ;睡 3
  7. 在执行 echo 后收集退出状态(很可能成功)。

有两种方法可以避免这种情况:第一种是使用eval,但这很危险并且有很多注意事项:将脚本替换为

#!/bin/bash

eval "$1 sleep 3"

使用这个脚本:

$ ./script "echo hello;"
hello
$

(并在延迟 3 秒后显示最终提示)。与 ./script "echo hello &&" 相同。 但这不是一个好主意。继续阅读。

作为一般规则,您应该避免(至少在 Bash 中)混合数据和代码:变量在这里保存数据(字符串),而不是代码。所以这个技术不是一个好技术。我说这不是一个好的,不仅因为有人曾经说过你不应该将数据与代码混合,而且因为如果你开始在你的“代码”中使用特殊字符,它将变得无法使用。例如,如果你想回显 * 符号,你将不得不使用笨拙的调用 ./script "echo\"*\";"。还有许多其他注意事项。

代码保存在函数或脚本中。使用函数:

say_hello_and_execute() {
echo hello; "$@"
}

然后导出此函数:export -f say_hello_and_execute 并将其用作脚本的参数:./script say_hello_and_execute

同样可以用脚本实现:调用下面的脚本say_hello_and_execute:

#!/bin/bash

echo hello; "$@"

然后 chmod +x say_hello_and_execute 并以 ./script ./say_hello_and_execute 运行脚本。


此答案试图回答您的问题。不过,如果您能准确地告诉我们您想要实现的目标会更好,因为可能会有更好的设计来实现这一目标。

关于从命令行传递字符串时的 Bash 怪癖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28236762/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com