我可以创建一个Ruby可执行文件是这样的(伪例子):
echo '#!/usr/bin/env ruby
puts %x[awk ''{print toupper($1)}'' #{STDIN} ]
' > pipes.rb
chmod +x pipes.rb
然后我就可以使用这个文件其他的Unix工具:
echo "a\nb\nc\nd" | ./pipes.rb | head -n2
# A
# B
但是,如果我需要在虚拟实例与另一个延伸打电话给AWK,这是行不通的:
echo '#!/usr/bin/env ruby
puts %x[awk ''{print toupper($1)}'' #{STDIN} | awk ''{ \
print tolower($1) \
}'']
' >! pipes2.rb
chmod +x pipes2.rb
echo "a\nb\nc\nd" | ./pipes2.rb | head -n2
# A
# B
# it should be: "a\nb"
的问题是,STDIN
被字符串化的,就像这样:#<IO:0x007fe18406ac58>
和散列被解释为注释,所以第二awk
声明被忽略(但出于某种原因,head
命令仍返回两行):
awk '{print toupper($1)}' #<IO:0x007fe18406ac58> | awk '{ print tolower($1)}'
我敢肯定有一个更好的方式来做到这一点(转义STDIN
参考?)。这是我能想到的最简单的可重复的例子。在我的真实脚本中,我允许多个输入源(标准输入或文件参数)。不可协商的要求是awk
代码需要对输入的引用,我不能在Ruby中逐行处理它。
任何想法?
UPDATE 继@ tadman的建议下,我已经做到了这一点,它的作品!:
#!/usr/bin/env ruby
require "open3"
Open3.popen3("awk '{print toupper($1)}'") do |cmd_in, cmd_out, cmd_err|
cmd_in.write(STDIN.read)
cmd_in.close
Open3.popen3("awk '{print tolower($1)}'") do |cmd_in2, cmd_out2, cmd_err2|
cmd_in2.write(cmd_out.read)
cmd_in2.close
puts cmd_out2.read
end
end
echo "aAA\nbBB\ncCC\ndDD" | ./pipes2.rb | head -n2
# aaa
# bbb
有没有办法来重构呢?
这是一个有点不寻常,看看'$ stdin'和'$ stdout'用于生产Ruby代码,它们是受Perl启发的全局变量。大多数时候你会看到使用'STDIN'和'STDOUT'。 'STDOUT.puts'也是多余的,因为默认情况下'puts'转到'STDOUT'。 – tadman 2014-10-31 15:55:27
好吧,我可以使用'STDIN'和'puts',但结果是一样的。 – nachocab 2014-10-31 15:59:23