运行 bash shell 脚本的输出作为 shell 命令?
Running the output of a bash shell script as a shell command?
我有一个名为 'test.sh' 的 shell 脚本:
#!/usr/bin/env bash
echo "echo 'hello';"
当我 运行 ./test.sh
它显然给出了这个输出:
echo 'hello';
现在这个输出也是一个有效的 shell 语句本身。如果我将此行复制并粘贴到 shell 并按回车键,它会显示
hello
到目前为止一切顺利。
但是我想一步完成,所以我尝试了这个:
$(./test.sh)
但是我现在得到:
'hello';
以防万一,我使用的是默认使用 zsh
shell 的 macOS 10.15.6 Catalina。我在 Linux 上使用 bash 尝试了相同的结果。
为了以防万一,我也尝试了 $('./test.sh')
或 $("./test.sh")
,但显然这没有什么区别。
可能有一些简单的解释和解决方案,但我没有看到。我做错了什么?
(编辑)也许这两个回声令人困惑,假设我的 test.sh 脚本包含以下内容:
echo "ls *.txt;"
如果我现在 ./test.sh
我得到
ls *.txt;
如果我将其复制并粘贴到 shell,它会按预期显示所有 .txt 文件。
但是如果我这样做 $(./test.sh)
我得到:
ls: *.txt;: No such file or directory
无论 test.sh 脚本输出什么,作为 shell 命令行执行的正确语法是什么?
你多了一个echo
。这是代码 (test.sh):
#!/bin/bash
echo "hello"
然后运行这样:$(./test.sh)
或"$(./test.sh)"
。它将启动 hello
命令。如果你想要 test.sh
到 运行 脚本,请在 test.sh
中使用 echo "./hello"
(使用 ./
)。
要在执行前显示命令,运行 this with bash -x test.sh
问题是命令替换($( )
的事情)是在解析命令行的过程中完成的——在解析并应用引号、分号和其他一些东西之后。结果,当那些引号、分号等成为命令行的一部分时,它们已经来不及做任何有用的事情了,它们只是没有特殊含义的普通字符。
这是您实际想要使用的少数情况之一 eval
:
eval "$(./test.sh)"
eval
所做的是重新运行 其参数的整个解析过程,因此它们中的任何 shell 语法(引号、分号等)都会得到完全解析。双引号是为了防止在命令替换之后但在结果传递给 eval
之前发生的一点点解析,这可能会导致奇怪的效果。
顺便说一句,eval
的名声通常很差,因为它会导致您不希望被视为 shell 语法的内容(如文件名等)被视为 shell 语法。但在这种情况下,这似乎正是您想要和期望的,所以它就是这样。
我有一个名为 'test.sh' 的 shell 脚本:
#!/usr/bin/env bash
echo "echo 'hello';"
当我 运行 ./test.sh
它显然给出了这个输出:
echo 'hello';
现在这个输出也是一个有效的 shell 语句本身。如果我将此行复制并粘贴到 shell 并按回车键,它会显示
hello
到目前为止一切顺利。
但是我想一步完成,所以我尝试了这个:
$(./test.sh)
但是我现在得到:
'hello';
以防万一,我使用的是默认使用 zsh
shell 的 macOS 10.15.6 Catalina。我在 Linux 上使用 bash 尝试了相同的结果。
为了以防万一,我也尝试了 $('./test.sh')
或 $("./test.sh")
,但显然这没有什么区别。
可能有一些简单的解释和解决方案,但我没有看到。我做错了什么?
(编辑)也许这两个回声令人困惑,假设我的 test.sh 脚本包含以下内容:
echo "ls *.txt;"
如果我现在 ./test.sh
我得到
ls *.txt;
如果我将其复制并粘贴到 shell,它会按预期显示所有 .txt 文件。
但是如果我这样做 $(./test.sh)
我得到:
ls: *.txt;: No such file or directory
无论 test.sh 脚本输出什么,作为 shell 命令行执行的正确语法是什么?
你多了一个echo
。这是代码 (test.sh):
#!/bin/bash
echo "hello"
然后运行这样:$(./test.sh)
或"$(./test.sh)"
。它将启动 hello
命令。如果你想要 test.sh
到 运行 脚本,请在 test.sh
中使用 echo "./hello"
(使用 ./
)。
要在执行前显示命令,运行 this with bash -x test.sh
问题是命令替换($( )
的事情)是在解析命令行的过程中完成的——在解析并应用引号、分号和其他一些东西之后。结果,当那些引号、分号等成为命令行的一部分时,它们已经来不及做任何有用的事情了,它们只是没有特殊含义的普通字符。
这是您实际想要使用的少数情况之一 eval
:
eval "$(./test.sh)"
eval
所做的是重新运行 其参数的整个解析过程,因此它们中的任何 shell 语法(引号、分号等)都会得到完全解析。双引号是为了防止在命令替换之后但在结果传递给 eval
之前发生的一点点解析,这可能会导致奇怪的效果。
顺便说一句,eval
的名声通常很差,因为它会导致您不希望被视为 shell 语法的内容(如文件名等)被视为 shell 语法。但在这种情况下,这似乎正是您想要和期望的,所以它就是这样。