简体   繁体   English

将 bash shell 脚本的输出作为 shell 命令运行?

[英]Running the output of a bash shell script as a shell command?

I have this shell script called 'test.sh' :我有一个名为 'test.sh' 的 shell 脚本:

#!/usr/bin/env bash

echo "echo 'hello';"

When I run ./test.sh it obviously gives this output:当我运行./test.sh它显然给出了这个输出:

echo 'hello'; echo '你好';

Now this output is also a valid shell statement itself.现在这个输出也是一个有效的 shell 语句本身。 If I copy & paste this line on the shell and press enter, it says如果我将此行复制并粘贴到外壳上并按 Enter,它会显示

hello你好

So far so good.到现在为止还挺好。
But I want to do this in one step, so I tried this:但我想一步完成,所以我尝试了这个:

$(./test.sh)

However I now get:但是我现在得到:

'hello'; '你好';

In case it matters, I'm using macOS 10.15.6 Catalina which uses the zsh shell by default.以防万一,我使用的是 macOS 10.15.6 Catalina,它默认使用zsh shell。 I tried the same on Linux using bash, same result.我在 Linux 上使用 bash 尝试了同样的方法,结果相同。

I also tried $('./test.sh') or $("./test.sh") just in case, but obviously that made no difference.我也试过$('./test.sh')$("./test.sh")以防万一,但显然这没有区别。

There's probably some simple explanation and solution to this, but I fail to see it.对此可能有一些简单的解释和解决方案,但我看不到。 What am I doing wrong?我究竟做错了什么?


(EDIT) Maybe the two echoes are confusing, suppose my test.sh script contains this: (编辑)也许这两个回声令人困惑,假设我的 test.sh 脚本包含以下内容:

echo "ls *.txt;"

If I now do ./test.sh I'm getting如果我现在做./test.sh我得到

ls *.txt; ls *.txt;

And if I copy and paste this on the shell it shows me all .txt files as expected.如果我将其复制并粘贴到 shell 上,它会按预期显示所有 .txt 文件。

However if I do $(./test.sh) I get:但是,如果我执行$(./test.sh)我得到:

ls: *.txt;: No such file or directory ls: *.txt;: 没有那个文件或目录

What is the right syntax to have whatever the test.sh script outputs, to be executed as a shell command line?将 test.sh 脚本输出作为 shell 命令行执行的正确语法是什么?

The problem is that command substitution (the $( ) thing) is done partway through the process of parsing the command line -- after it's parsed and applied quotes, semicolons, and a bunch of other things.问题是命令替换( $( )事情)是在解析命令行的过程中完成的——在解析并应用引号、分号和其他一些东西之后。 As a result, by the time those quotes, the semicolon, etc are part of the command line, it's too late for them to do anything useful, and they're just ordinary characters with no special meaning.结果,当这些引号、分号等成为命令行的一部分时,它们做任何有用的事情都为时已晚,它们只是没有特殊含义的普通字符。

This is one of those few cases where you actually want to use eval :这是您真正想要使用eval少数情况之一:

eval "$(./test.sh)"

What eval does is re-run the entire parsing process on its arguments, so any shell syntax in them (quotes, semicolons, whatever) gets fully parsed. eval所做的是对其参数重新运行整个解析过程,因此它们中的任何 shell 语法(引号、分号等)都会被完全解析。 The double-quotes are there to prevent that little bit of parsing that would've happened after the command substitution but before the result got passed to eval , which can cause weird effects.双引号是为了防止在命令替换之后但在结果传递给eval之前发生的一点点解析,这可能会导致奇怪的效果。

BTW, eval has a generally bad reputation because it can cause things you didn't expect to be treated as shell syntax (like filenames, etc) to be treated as shell syntax.顺便说一句, eval名声通常很差,因为它可能导致您不希望被视为 shell 语法的东西(如文件名等)被视为 shell 语法。 But in this case, that seems to be exactly what you want and expect, so it's just the thing.但在这种情况下,这似乎正是您想要和期望的,所以就是这样。

You have an extra echo .你有一个额外的echo Here is the code (test.sh):这是代码(test.sh):

#!/bin/bash
echo "hello"

Then run it like that: $(./test.sh) or "$(./test.sh)" .然后像这样运行它: $(./test.sh)"$(./test.sh)" It will launch hello command.它将启动hello命令。 If you want test.sh to run a script, use echo "./hello" in test.sh (with ./ ).如果您希望test.sh运行脚本,请在test.sh使用echo "./hello" (带有./ )。

To display commands before execution, run this with bash -x test.sh要在执行前显示命令,请使用bash -x test.sh运行此命令

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM