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

kch*_*kch 77 unix bash shell pipe

我很清楚source(又名.)实用程序,它将从文件中获取内容并在当前shell中执行它们.

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

$ ls | sed ... | sh
Run Code Online (Sandbox Code Playgroud)

ls只是一个随机的例子,原始文本可以是任何东西.sed也是一个转换文本的例子.有趣的是sh.我管道我得到的任何东西sh,它运行它.

我的问题是,这意味着启动一个新的子shell.我宁愿让命令在我当前的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
Run Code Online (Sandbox Code Playgroud)

这确保所有.doc文件的扩展名都是小写的.

顺便说一下,可以处理xargs,但除此之外.

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

所以,当我运行前者时,它会马上退出,没有任何反应.

Jul*_*ano 117

eval命令存在于此目的.

eval "$( ls | sed... )"
Run Code Online (Sandbox Code Playgroud)

更多来自bash手册:

EVAL

          eval [arguments]
Run Code Online (Sandbox Code Playgroud)

参数连接在一起形成一个命令,然后读取并执行该命令,并将其退出状态作为eval的退出状态返回.如果没有参数或只有空参数,则返回状态为零.

  • 这里唯一的问题是你可能需要插入;来分隔你的命令.我自己使用这个方法来处理AIX,Sun,HP和Linux. (7认同)
  • 这很棒.但是,对于我的用例,我最终不得不在$()周围加上引号:`eval'$(ssh remote-host'cat~/.bash_profile')"`注意我确实使用了bash 3.2 . (3认同)
  • 这对我来说很有效,但接受的答案却没有. (3认同)
  • Tanktalus,感谢您的评论,它让我的脚本发挥作用。在我的机器上, eval 不会在换行符上分隔命令,并且即使使用分号,使用 source 也不起作用。使用分号进行评估是解决方案。我希望能给你一些分数。 (2认同)
  • @MilanBabuškov:我为你排名他;-) (2认同)

mar*_*k4o 80

$ ls | sed ... | source /dev/stdin
Run Code Online (Sandbox Code Playgroud)

更新:这适用于bash 4.0,以及tcsh和dash(如果你source改为.).显然这是bash 3.2中的错误.从bash 4.0发行说明:

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

  • 只是一句话:这个似乎没有按预期处理导出语句.如果管道字符串具有导出语句,则导出变量在之后的终端环境中不可用,而使用eval导出也可以完美地运行. (9认同)
  • 我认为这很巧妙,直到我在 msys/mingw(没有 /dev 文件夹(甚至没有设备)!我尝试了许多 eval、$() 和反引号``的组合。我无法做任何事情,所以我最后只是将输出重定向到一个临时文件,获取临时文件,然后删除它。基本上是“sed ... > /tmp/$$.tmp && . /tmp/$$.tmp && rm /tmp/ $$.tmp"。有人有没有临时文件的 msys/mingw 解决方案吗??? (2认同)
  • 在没有设置lastpipe选项的bash中,这会创建一个子shell,就像`|一样 bash` 会 (2认同)

rab*_*sky 36

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

无论如何 - 我不喜欢这个source /dev/stdin答案,但我认为我发现了一个更好的答案.实际上看起来很简单:

echo ls -la | xargs xargs
Run Code Online (Sandbox Code Playgroud)

很好,对吧?实际上,这仍然没有做你想要的,因为如果你有多行,它会将它们连接成一个命令,而不是分别运行每个命令.所以我找到的解决方案是:

ls | ... | xargs -L 1 xargs
Run Code Online (Sandbox Code Playgroud)

-L 1选项意味着每个命令执行使用(最多)1行.注意:如果您的行以尾随空格结尾,它将与下一行连接!因此,请确保每一行以非空格结束.

最后,你可以做到

ls | ... | xargs -L 1 xargs -t
Run Code Online (Sandbox Code Playgroud)

查看执行的命令(-t是详细的).

希望有人读到这个!

  • 非常好,但似乎不适用于我的mac :-( (4认同)

ris*_*hta 28

尝试使用进程替换,它将命令的输出替换为可以获取的临时文件:

source <(echo id)
Run Code Online (Sandbox Code Playgroud)

  • 这是什么样的巫术? (6认同)
  • 这也是我的第一个想法。虽然我更喜欢 eval 解决方案。@PauloTorrens &lt;(xyz) 只是执行 xyz 并将 &lt;(xyz) 替换为将写入 xyz 输出的文件的名称。很容易理解它是如何工作的,例如:`echo &lt;(echo id)`,给出输出`/dev/fd/12`(12是一个例子),`cat &lt;(echo id)`,给出输出输出`id`,然后`source &lt;(echo id)`给出与简单写入`id`相同的输出 (2认同)
  • @PauloTorrens,这称为[流程替换](http://tldp.org/LDP/abs/html/process-sub.html).请参阅链接的文档以获取官方解释,但简短的回答是"<()"是一种特殊的语法,专为此类案例而设计. (2认同)
  • @PauloTorrens,这是一个特殊的语法,仅用于进程替换. (2认同)

Geo*_*xon 6

我相信这是问题的"正确答案":

ls | sed ... | while read line; do $line; done
Run Code Online (Sandbox Code Playgroud)

也就是说,人们可以进入while循环; 该read命令命令从它的一条线stdin,并将其分配给变量$line.$line然后成为循环中执行的命令; 并继续直到输入中没有其他行.

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


cha*_*aos 5

`ls | sed ...`
Run Code Online (Sandbox Code Playgroud)

我有点感觉象ls | sed ... | source -是漂亮,但不幸的是source不理解-的意思stdin.