从标准输入中读取源代码(在OSX上的Bash)

4
我正在尝试做类似这样的事情。
 ruby test.rb | source /dev/stdin

test.rb只是打印出cd /。没有错误,但也没有任何作用。如果我使用以下命令:

 ruby test.rb > /tmp/eraseme2352; source /tmp/eraseme2352

它能正常工作,但我想避免中间文件。

编辑:整个重点在于当命令完成时需要保留更改。抱歉之前没有表述清楚。


感谢Jonathan在这个问题上的耐心和帮助。 - Dan Rosenstark
@Jonathan:尝试使用source <(echo 'echo a b c')或者source <(echo 'testvar=TestVal'); echo $testvar - Dennis Williamson
@Dennis:我试过了,令我惊讶的是它似乎没有起作用。我的操作系统是MacOS X 10.6.3,使用的是bash 3.2.48版本(其中.48可能是苹果版本号的标识)。我刚刚重新尝试了你的示例;我还尝试了启用“set -x”。但它似乎没有做任何合理的事情。嗯...在Bash 4.1中(我刚刚编译并在今天早些时候下载了它),它按照你的期望工作。因此,在由Apple提供的Bash 3.2.48和GNU提供的Bash 4.1之间似乎存在一个错误修复。 - Jonathan Leffler
@Jonathan:我刚在CygWin下的Bash 3.2.49(23)-release中测试了一下,它不起作用。但是,在Ubuntu中的4.0.33(1)-release中可以,所以你可能是正确的关于bug fix的事情,但我没有在http://tiswww.case.edu/php/chet/bash/NEWS找到相关参考。 - Dennis Williamson
“/eraseme” - 你肯定不会把临时文件写在根目录下吧? - Dennis Williamson
显示剩余5条评论
6个回答

6
您可以尝试:
$(ruby test.rb)

$(...)表示告诉Bash执行括号内命令所产生的输出。


在这里,有没有办法让Shell不显示正在运行的命令? - Dan Rosenstark
1
请注意,这仅适用于Ruby脚本仅输出单个命令行的情况。如果它输出多行,它们将被合并成一个大命令。 - Thomas
@Thomas,哦,没想到那个。我现在会取消标记这个作为最佳答案,希望能得到更好的最佳答案。 - Dan Rosenstark
@Thomas,实际上这不是真的。不确定为什么,但在尝试多行时它完美地工作。 - Dan Rosenstark
如果这对你有效,那太好了。但是 $(echo -e 'ls\ncd') 给我的结果是 ls: cannot access cd: No such file or directory。快速浏览一下 bash 的 man 手册,显示这可能与 IFS 的值有关。 - Thomas
@Thomas,不确定发生了什么。你的测试对我也失败了,但这个'tell app "Terminal" to do script "$(paste_env)" '可以工作,结果是很多行代码。有点棘手,不太确定。 - Dan Rosenstark

3
以下代码在我的Mac OS X 10.6.7上可以运行:
/bin/bash

sw_vers   # Mac OS X 10.6.7

bash --version   # GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin10.0)

source /dev/stdin <<<'echo a b c'

source /dev/stdin  <<< "$(ruby -e 'puts "echo a b c"')"

source /dev/stdin <<<'testvar=TestVal'; echo $testvar


source /dev/stdin <<-'EOF'
echo a b c
EOF

source /dev/stdin <<-'EOF'
$(ruby -e 'puts "echo a b c"') 
EOF

(
source /dev/stdin <<-'EOF'
testvar=TestVal
EOF
echo $testvar
)

3
eval `ruby test.rb`

你为什么需要 eval - Thomas
1
@Thomas:因为例如eval $(echo 'var1=27;var2=38')按预期工作,在当前shell中设置这些变量。没有eval,它将被执行为一个命令并给出错误:“var1=27;var2=38: 命令未找到”。 - Dennis Williamson
@Dennis WilliamsonпјҡеҸҚеј•еҸ·е’Ң $() жҳҜзӯүд»·зҡ„еҗ—пјҹйӮЈжҲ‘еә”иҜҘжҠҠиҝҷдёӘж Үи®°дёәжңҖдҪізӯ”жЎҲпјҢжҳҜеҗ—пјҹ - Dan Rosenstark
2
@yar:它们大多数是等价的,但是$()首选 - Dennis Williamson

2

在更有经验的Bash黑客出现之前,你可以这样做:

for c in `ruby test.rb` ; do $c ; done

注意:这并不是你想要的结果。请阅读注释!


那也可能很有用。谢谢。 - Dan Rosenstark
这将把 Ruby 脚本的输出中的每个“单词”(以空格分隔的标记)视为一个命令。如果没有命令带参数,它将可以工作。如果任何命令带有参数,它将无法工作。 - Jonathan Leffler
问题在于这就是我试图避免的问题:学习Shell脚本。有没有办法让我格式化输出,使其适用于多行?我真正想做的是 | source - Dan Rosenstark
@Jonathan:啊,糟糕。我只测试了简单的命令。会留下一个警告。 - Thomas

1

bash(不是sh):

while read -a line
do
  "${line[@]}"
done < <(somescript)

命令参数中的空格需要进行反斜杠转义才能正常工作。


谢谢,但我认为我会选择eval $()作为最佳答案。 - Dan Rosenstark

0

只是怎么样呢

ruby test.rb | bash

1
这将在子shell中执行命令。任何副作用,如更改目录或设置环境变量都将丢失。 - Thomas
确实如此。不使用子shell并没有被列为要求……但$()语法看起来更好。 - Matti Virkkunen
1
这在示例代码中隐含地作为要求。 - Dan Rosenstark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接