将带有变量的字符串作为命令执行

将带有变量的字符串作为命令执行

我正在尝试在 bash 脚本中执行一个字符串。字符串包含变量(因此我可以根据情况替换一些 CLI 参数)。

问题是当我使用包含变量时--argument=value,一切都会崩溃,并给出错误:

Missing trailing-' in remote-shell command.

示例代码:

#!/bin/bash

rsync_path="/usr/bin/rsync -azhrP"
rsync_ssh_cmd="--rsh='ssh -o Compression=no'"

`$rsync_path /path/to/file $rsync_ssh_cmd username@localhost:/tmp`

如果我只是echo这段代码中的最后一个字符串,它看起来不错。但是,如果我尝试从脚本执行该字符串,它不会按预期执行。

我找到了一个解决方法 - 如果我尝试一切都会好起来

eval "my-command-string"

代替

`my-command-string`

或者

(my-command-string)

为什么会这样呢?我怎样才能(我真的应该吗?)避免使用eval

我使用 bash 4.3.11(1)-release (x86_64-pc-linux-gnu)(Kubuntu 14.04.3)。

答案1

好的。您可以eval通过想出一些其他方法来两次评估字符串来避免使用。无论你做什么,你都需要两次评估因为你的要求是解析一个解析

我的意思是:

this is 'a parsed" command string"'

^ 计算结果为 3:

1: this 2: is 3: a parsed" command string"

3 中的引号并不重要——它们根本不重要,因为它们只是单词中的某些字符'原始命令行中使用的语法引号做过很重要,因为它们被 shell 的解析器解释来分隔单词。其中的任何内容都只是单词的一部分。

所以,如果你想得到更多的的话来自a单身的,预解析的word,你必须将它作为输入返回给 shell。这就是它的全部内容 — shell 处理输入上的输入引号。引号用于以有意义的方式转义和分隔输入。如果贝壳继续这样下去,那将毫无意义,而且相当可怕。最终全部输入将被评估为零!

所以你需要一个第二次评价。你无法从$( 命令替换中得到它)中得到它,因为它们不处理输入,他们处理输出。任何副作用$词扩展您可能会将其等同于更多的生成事实并非如此——也就是说场地-分裂。场地- 分裂$IFS*通配由 shell 执行输入在解析过程中已经被定界。

现在eval的全部目的是eval乌阿特作为输入shell 已经接收到的一些字符串作为输入。这是确切地这是正确的工具,但如果您坚持的话,我们也可以采用其他方式。

一种方法是.获取自己的输出。

string="printf '<%s>\n' 'these are' 'some words' 'i will evaluate again'"
. /dev/fd/0 <<!
$string
!

在该示例中,外壳评估作为输入它自己的输出。有用:

<these are>
<some words>
<i will evaluate again>

您可以通过调用另一个 shell 来评估您的输出作为其输入来完成此操作:

sh -c "$string"

...输出是相同的。你可以延迟通过定义 shell 来输入alias

alias evaled="$string"
evaled

...同样的输出。

最多直接的方法是:

eval "$string"

效果与所有其他示例几乎相同,但这次我实际上是使用命令完成的命名的为了我想做的事。

eval因为人们不明白它的作用或为什么要使用它,所以受到了不好的批评。问题是,如果您不了解这样做的效果,则不应使用它。并且很容易迷失方向:命令被评估两次——这比正常情况要多——而且对于大多数人来说,时间通常足以浏览此网站。

所以,你应该eval在这种情况下使用做你想做的这件事,因为你想做的是eval一个字符串。我不妄下判断为什么你想要eval字符串,虽然我希望有更好的方法来做到这一点,但是当你想要 shell 字符串的内容时评价的作为 shell 输入,您应该使用eval.

答案2

由于嵌入引号,您遇到此问题:Bash常见问题解答

这是工作环境:

#!/bin/bash

rsync_path="/usr/bin/rsync -azhrP"
rsync_ssh_cmd=(--rsh='ssh \-o Compression=no')
`$rsync_path /path/to/file $rsync_ssh_cmd  root@localhost:/tmp`

[概念证明]

[root@localhost ~]# bash -x  /tmp/c.sh
+ rsync_path='/usr/bin/rsync -azhrP'
+ rsync_ssh_cmd=(--rsh='ssh \-o Compression=no')
++ /usr/bin/rsync -azhrP /path/to/file --rsh=ssh '\-o' Compression=no root@localhost:/tmp
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/root/.ssh/id_rsa' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
bad permissions: ignore key: /root/.ssh/id_rsa
root@localhost's password:

相关内容