使用变量作为命令执行字符串

Ant*_*ioK 6 bash

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

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

Missing trailing-' in remote-shell command.
Run Code Online (Sandbox Code Playgroud)

示例代码:

#!/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`
Run Code Online (Sandbox Code Playgroud)

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

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

eval "my-command-string"
Run Code Online (Sandbox Code Playgroud)

代替

`my-command-string`
Run Code Online (Sandbox Code Playgroud)

或者

(my-command-string)
Run Code Online (Sandbox Code Playgroud)

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

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

mik*_*erv 7

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

我的意思是:

this is 'a parsed" command string"'
Run Code Online (Sandbox Code Playgroud)

^ 结果为 3 个词:

1: this 2: is 3: a parsed" command string"
Run Code Online (Sandbox Code Playgroud)

3 中的引号并不重要——它们根本不重要,因为它们只是单词中的一些字符。'原始命令行中使用的语法引号确实很重要,因为 shell 的解析器将它们解释为分隔单词. 里面的任何东西都只是这个词的一部分。

所以,如果你想获得更多的从一个字单,预分析的话,你必须给它回shell作为输入。这就是它的全部内容——shell 在输入时处理输入引号。引号用于以有意义的方式转义和分隔输入。如果外壳只是保持它,那将毫无意义——而且相当可怕。最终,所有输入都会被评估为空!

所以你需要第二次评估。你不能从$( 命令替换中得到它,)因为它们不处理input,它们处理output。您可能等同于生成更多单词的$单词扩展的任何副作用实际上并非如此 - 即字段拆分。字段-splitting上和通配符由壳进行后输入词语已经在解析过程界定。$IFS*

现在eval的整个目的是eval审视你们作为输入其外壳已经收到输入一些字符串。它正是实现此目的的正确工具,但如果您坚持,我们也可以采用其他方式。

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

string="printf '<%s>\n' 'these are' 'some words' 'i will evaluate again'"
. /dev/fd/0 <<!
$string
!
Run Code Online (Sandbox Code Playgroud)

在该示例中,shell将其自己的output评估为input。有用:

<these are>
<some words>
<i will evaluate again>
Run Code Online (Sandbox Code Playgroud)

您可以通过调用另一个 shell 来评估您的输出作为其输入来实现:

sh -c "$string"
Run Code Online (Sandbox Code Playgroud)

...输出是一样的。您可以通过定义 shell来延迟输入alias:

alias evaled="$string"
evaled
Run Code Online (Sandbox Code Playgroud)

...再次,相同的输出。

最直接的方法是:

eval "$string"
Run Code Online (Sandbox Code Playgroud)

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

eval获得不好的名声,因为人们不了解它的作用或为什么使用它。问题是,如果您不了解这样做的影响,就不应该使用它。它可以很容易失去跟踪:命令进行评估的两倍-这就是一旦超过正常和一个时间通常绰绰有余是为大多数人在这个网站拉闸。

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


Khe*_*dun 1

由于嵌入引号,您遇到此问题:BashFAQ

这是工作环境:

#!/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`
Run Code Online (Sandbox Code Playgroud)

[概念证明]

[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:
Run Code Online (Sandbox Code Playgroud)