如何在当前 shell 中执行命令的输出?
Posted
技术标签:
【中文标题】如何在当前 shell 中执行命令的输出?【英文标题】:How to execute the output of a command within the current shell? 【发布时间】:2010-11-19 18:42:48 【问题描述】:我非常了解source
(又名.
)实用程序,该实用程序将从文件中获取内容并在当前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 周围添加引号。 有什么好的理由必须在原始 shell 中运行它吗? - 这些示例不会操纵当前的 shell,因此您这样做一无所获。快速的解决方案是将输出重定向到一个文件并获取该文件 @kaleb 输出运行良好。在这种特殊情况下,即使我通过管道连接到 sh。文件名是空间安全的,但感谢您的注意。 @nos 原始外壳上的 git 环境变量。再一次,这些只是例子。这个问题是终身的。 source /dev/stdin 在需要分配变量时对我不起作用。 freenode bash 上的 geirha 将我指向 mywiki.wooledge.org/BashFAQ/024 并建议我尝试一个对我有用的进程替换源 【参考方案1】:eval
命令就是为此目的而存在的。
eval "$( ls | sed... )"
更多来自bash manual:
评估
eval [arguments]
参数连接在一起 成一个命令,其中 然后被读取并执行,它的 作为退出返回的退出状态 评估的状态。如果没有 参数或只有空参数, 返回状态为零。
【讨论】:
这里唯一的问题是您可能需要插入 ; 来分隔您的命令。我自己使用这种方法在 AIX、Sun、HP 和 Linux 上工作。 Tanktalus,感谢您的评论,它使我的脚本正常工作。在我的机器上,eval 不会在换行符上分隔命令,并且即使使用分号也无法使用 source。带分号的 Eval 是解决方案。我希望我能给你一些分数。 @MilanBabuškov:我给他排名了 ;-) 这太棒了。但是,对于我的用例,我最终不得不在 $() 周围加上引号,如下所示:eval "$( ssh remote-host 'cat ~/.bash_profile' )"
请注意,我确实使用的是 bash 3.2。
这适用于我接受的答案没有。【参考方案2】:
$ ls | sed ... | source /dev/stdin
更新:这适用于 bash 4.0,以及 tcsh 和 dash(如果您将 source
更改为 .
)。显然这在 bash 3.2 中是错误的。来自bash 4.0 release notes:
修复了导致 `.' 的错误无法从非常规文件(例如设备或命名管道)读取和执行命令。
【讨论】:
哦,既然你列出了 shell,它也可以在 zsh 中工作。 我认为这很巧妙,直到我在 msys/mingw 中尝试过(没有 /dev 文件夹(甚至没有设备)!我尝试了 eval、$() 和反引号的许多组合.我什么都做不了,所以我最后只是将输出重定向到一个临时文件,获取临时文件,然后将其删除。基本上“sed ... > /tmp/$$.tmp && . /tmp/$ $.tmp && rm /tmp/$$.tmp"。有人有没有临时文件的 msys/mingw 解决方案吗??? 只是备注:这似乎没有按预期处理导出语句。如果管道字符串有一个导出语句,则 exportet 变量在您的终端环境中不可用,而使用 eval 导出也可以完美地工作。 在没有设置 lastpipe 选项的 bash 中,这会创建一个子 shell,就像| bash
会
鉴于 MacOS X 通常有 bash 3.2(也许 Yosemite 有 4.0?),并且在我的用例中需要 lastpipe 技巧(通过使用 sed 预处理每一行来导出文件中的所有变量添加“导出”)我选择使用eval "$(sed ...)"
方法-但感谢3.2错误提示!【参考方案3】:
哇,我知道这是一个老问题,但我最近发现自己遇到了同样的问题(这就是我来到这里的原因)。
无论如何 - 我不喜欢 source /dev/stdin
的答案,但我想我找到了更好的答案。其实很简单:
echo ls -la | xargs xargs
很好,对吧?实际上,这仍然不能满足您的要求,因为如果您有多行,它会将它们连接到一个命令中,而不是单独运行每个命令。所以我找到的解决方案是:
ls | ... | xargs -L 1 xargs
-L 1
选项意味着您(最多)每次命令执行使用 1 行。 注意:如果您的行以尾随空格结尾,它将与下一行连接!所以请确保每一行都以非空格结尾。
终于可以了
ls | ... | xargs -L 1 xargs -t
查看执行了哪些命令(-t 是详细的)。
希望有人读到这篇文章!
【讨论】:
【参考方案4】:尝试使用process substitution,它将命令的输出替换为可以获取的临时文件:
source <(echo id)
【讨论】:
这是什么魔法? 这也是我的第一个想法。虽然我更喜欢 eval 解决方案。 @PauloTorrens echo <(echo id),给出输出/dev/fd/12
(12 是一个例子),cat <(echo id)
,给出输出id
,然后source <(echo id)
给出相同的输出就像简单地写id
@PauloTorrens,这叫process substitution。有关官方解释,请参阅链接文档,但简短的回答是“
@MarkStosberg,你知道这是一种特殊的语法,还是只是 (...)
重定向的子shell?
@PauloTorrens,这是一种特殊语法,仅用于进程替换。【参考方案5】:
我相信这是问题的“正确答案”:
ls | sed ... | while read line; do $line; done
也就是说,可以通过管道进入while
循环; read
命令命令从其stdin
中取出一行并将其分配给变量$line
。 $line
然后成为循环内执行的命令;它会一直持续到其输入中没有其他行为止。
这仍然不适用于某些控制结构(如另一个循环),但在这种情况下它符合要求。
【讨论】:
【参考方案6】:`ls | sed ...`
我觉得ls | sed ... | source -
会更漂亮,但不幸的是source
不理解-
的意思是stdin
。
【讨论】:
看到mark4o的回答后,是不是一直都在我们的脸上感觉呢? 嘿,是的。我从不记得有那种东西存在。【参考方案7】:要在 bash 3.2 (macos) 上使用 mark4o 的解决方案,可以使用此处的字符串来代替本示例中的管道:
. /dev/stdin <<< "$(grep '^alias' ~/.profile)"
【讨论】:
或使用反引号:. /dev/stdin 【参考方案8】:我认为您的解决方案是用反引号替换命令:http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html
参见第 3.4.5 节
【讨论】:
如果你使用 bash,$( )
语法可能是首选。 '当然反引号在 more shells 中工作......
$(command) 和 $((1+1)) 在所有 posix shell 中工作。我认为许多人被 vim 标记为语法错误而推迟,但这只是因为 vim 突出显示了很少使用的原始 Bourne shell。要让 vim 正确突出显示,请将其放入 .vimrc 中: let g:is_posix = 1【参考方案9】:
那为什么不用source
呢?
$ ls | sed ... > out.sh ; source out.sh
【讨论】:
他提到临时文件很恶心。以上是关于如何在当前 shell 中执行命令的输出?的主要内容,如果未能解决你的问题,请参考以下文章
如何将一shell脚本中的每一步命令执行结果输出到指定日志文件中