如何在当前shell中执行命令的输出?


89

我很了解source(aka .)实用程序,它将从文件中获取内容并在当前shell中执行它们。

现在,我将一些文本转换为shell命令,然后运行它们,如下所示:

$ ls | sed ... | sh

ls只是一个随机的例子,原始文本可以是任何东西。sed也只是一个转换文本的示例。有趣的是sh。我用管道输送我所得到的一切sh,然后运行它。

我的问题是,这意味着启动一个新的子外壳。我宁愿命令在我当前的shell中运行。就像我能够使用source some-file,如果我在文本文件中包含命令。

我不想创建一个临时文件,因为感觉很脏。

另外,我想以与当前shell完全相同的特性启动子shell。

更新

好的,使用反引号的解决方案当然可以工作,但是我经常需要在检查和更改输出时执行此操作,因此我更希望是否有一种将结果最终传递给某些对象的方法。

悲伤的更新

嗯,这/dev/stdin东西看起来很漂亮,但是在更复杂的情况下,它没有用。

所以,我有这个:

find . -type f -iname '*.doc' | ack -v '\.doc$' | perl -pe 's/^((.*)\.doc)$/git mv -f $1 $2.doc/i' | source /dev/stdin

这样可以确保所有.doc文件的扩展名都小写。

顺便说一句,可以使用进行处理xargs,但这不重要。

find . -type f -iname '*.doc' | ack -v '\.doc$' | perl -pe 's/^((.*)\.doc)$/$1 $2.doc/i' | xargs -L1 git mv

因此,当我运行前者时,它将立即退出,没有任何反应。


当您先通过管道传输到临时文件然后将其作为源时,复杂的命令是否起作用?如果不是,生成的输出有什么问题?如果文件名中包含空格或某些序列未正确转义,则命令的输出将无效。我想至少在$ 1和$ 2.doc附近添加报价。
Kaleb Pederson

是否有充分的理由必须在原始Shell中运行它?-这些示例不会操纵当前的shell,因此您一无所获。快速的解决办法是将输出重定向到一个文件和源该文件虽然

@kaleb输出运行正常。在这种情况下,即使我用管道传输到sh。文件名是空间安全的,但是请注意。@nos原始外壳上的git环境变量。同样,这些只是示例。问题是生命。
kch

当需要分配变量时,源代码/ dev / stdin不适用于我。freenode bash上的geirha将我指向mywiki.wooledge.org/BashFAQ/024,并建议我尝试对我有用的进程替换源<(命令)
srcerer 2015年

Answers:


85
$ ls | sed ... | source /dev/stdin

更新:这适用于bash 4.0,tcsh和破折号(如果更改source.)。显然,这是bash 3.2中的错误。从bash 4.0发行说明中

修复了导致“。”的错误。无法从非常规文件(例如设备或命名管道)读取和执行命令。


好。然后到bash 4.0。
kch

哦,既然您要列出这些外壳,它也可以在zsh中使用。
kch

1
我一直认为这很巧妙,直到我在msys / mingw中尝试过(那里没有/ dev文件夹(甚至没有设备)!我尝试了eval,$()和反引号的许多组合``。我什么都做不了。 ,所以我最终只是将输出重定向到一个临时文件中,获取了该临时文件,然后将其删除了。基本上是“ sed ...> /tmp/$$.tmp &&。/tmp/$$.tmp && rm / tmp / $$。tmp”。任何人都可以得到没有临时文件的msys / mingw解决方案??
chriv 2012年

10
只是一句话:该代码似乎无法按预期处理导出语句。如果管道字符串具有export语句,则exportet变量此后在您的终端环境中不可用,而使用eval export也可以完美地工作。
菲尔(Phil)

1
鉴于MacOS X通常具有bash 3.2(也许优胜美地具有4.0?),并且在我的用例中需要lastpipe技巧(通过使用sed预处理每一行以导出'export'来导出文件中的所有变量),我选择了与该eval "$(sed ...)"方法一起使用-但是感谢3.2错误提示!
Alex Dupuy 2015年

133

eval命令就是为此目的而存在的。

eval "$( ls | sed... )"

bash手册中的更多内容:

评估

          eval [arguments]

这些参数被串联到一个命令中,然后被读取并执行,并且其退出状态作为eval的退出状态返回。如果没有参数或只有空参数,则返回状态为零。


8
唯一的问题是您可能需要插入;来分隔命令。我自己使用此方法在AIX,Sun,HP和Linux上工作。
Tanktalus

Tanktalus,感谢您的评论,它使我的脚本正常工作。在我的机器上,eval不会在换行符之间分隔命令,即使使用分号,也无法使用source。用分号评估是解决方案。我希望我能给你点意见。
米兰Babuškov2011年

2
@MilanBabuškov:我为你排名他;-)
Phil

3
太好了 但是,对于我的用例,我最终不得不在$()周围加上引号,如下所示:eval "$( ssh remote-host 'cat ~/.bash_profile' )"请注意,我确实在使用bash 3.2。
Zachary Murray

3
这对我有用,但无法接受。
Dan Tenenbaum 2014年

37

哇,我知道这是一个老问题,但是最近我发现自己也遇到了同样的问题(这就是我到达这里的方式)。

无论如何-我不喜欢这个source /dev/stdin答案,但我想我找到了一个更好的答案。实际上这看似简单:

echo ls -la | xargs xargs

好吧 实际上,这仍然不能满足您的要求,因为如果您有多行,它将把它们合并为一个命令,而不是分别运行每个命令。所以我找到的解决方案是:

ls | ... | xargs -L 1 xargs

-L 1选项表示每个命令执行最多使用1行。注意:如果您的行末尾有空格,它将与下一行连接!因此,请确保每行以非空格结尾。

最后,你可以做

ls | ... | xargs -L 1 xargs -t

看看执行了什么命令(-t是冗长的)。

希望有人阅读!


30

尝试使用进程替换,它用一个临时文件替换命令的输出,然后可以使用该文件来获取:

source <(echo id)

7
这是什么法术?
paulotorrens 2015年

这也是我的第一个想法。虽然我更喜欢评估解决方案。@PauloTorrens <(xyz)仅执行xyz,并将<(xyz)替换为将写入xyz输出的文件名。通过执行以下操作非常容易理解它的工作方式:例如echo <(echo id),给出输出/dev/fd/12(示例为12)cat <(echo id),给出输出id,然后source <(echo id)给出与简单编写相同的输出id
netigger

2
@PauloTorrens,这称为流程替换。请参阅链接的文档以获取官方解释,但简短的答案是“ <()”是专门为此类情况设计的特殊语法。
Mark Stosberg '16

1
@MarkStosberg,您知道这是一种特殊语法还是只是(...)重定向了一个子外壳?
paulotorrens's

2
@PauloTorrens,这是仅用于进程替换的特殊语法。
Mark Stosberg '16

6

我相信这是该问题的“正确答案”:

ls | sed ... | while read line; do $line; done

就是说,一个人可以通过管道while循环。该read命令命令占一行从其stdin并给它分配给变量$line$line然后成为在循环内执行的命令;并一直持续到其输入中没有其他行为止。

这仍然不适用于某些控制结构(如另一个循环),但在这种情况下很合适。


5
`ls | sed ...`

我觉得自己ls | sed ... | source -会更漂亮,但不幸的source是,这并不-意味着stdin


看到mark4o的答案之后,这难道不是一直都在面对吗?
kch

嗯是的 我永远不记得那个东西存在。
混乱

1

我认为您的解决方案是使用反引号替换命令:http : //tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html

见3.4.5节


3
如果您使用的是bash,则$( )首选语法。“课程反引号在更多的炮弹中起作用...
dmckee ---前主持人小猫,

6
$(command)和$((1 + 1))在所有posix shell中均有效。我认为许多人把vim标记为语法错误而推迟了,但这只是因为vim突出了很少使用的原始Bourne shell。要使vim正确突出显示,请将其放入您的.vimrc中:让g:is_posix = 1
pixelbeat

1

要在bash 3.2(macos)上使用mark4o的解决方案,可以使用here字符串而不是本示例中的管道:

. /dev/stdin <<< "$(grep '^alias' ~/.profile)"

或使用反引号:。/ dev / stdin <<<`grep'^ alias'〜/ .profile`
William H. Hooper

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.