如何在Ruby中的unix管道中使用$stdout和$stdin?
我可以创建如下ruby可执行文件(虚拟示例): 然后,我可以将此文件用于其他unix工具:如何在Ruby中的unix管道中使用$stdout和$stdin?,ruby,awk,pipe,stdout,stdin,Ruby,Awk,Pipe,Stdout,Stdin,我可以创建如下ruby可执行文件(虚拟示例): 然后,我可以将此文件用于其他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) \ }'']
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
被字符串化为:#
并且散列被解释为注释,因此第二个awk
语句被忽略(但出于某种原因,head
命令仍然返回两行):
有办法重构吗?这里的问题是,您直接提供
$stdin
,而不是使用它做任何事情。这就是Ruby将其呈现为原始对象的原因。它是一个文件句柄,除非你对它使用一个方法,而不是原始数据
您需要的是从该文件句柄获取所有内容:
$stdin.read
如果要使用Ruby,则没有理由使用awk
:
#!/usr/bin/env ruby
puts STDIN.read.upcase
如果要将换行保留为“\n”
,请执行以下操作:
puts STDIN.read.upcase.inspect
如果您承诺使用外部命令:
require 'open3'
Open3.popen3("awk '{print toupper($1)}'") do |cmd_in, cmd_out, cmd_err|
# Read from our STDIN and push through to the command's STDIN
cmd_in.write(STDIN.read)
# Close STDIN on the command to tell it we're finished writing.
cmd_in.close
# Read result from command's STDOUT and write to our STDOUT
puts cmd_out.read.inspect
end
好吧,我找到了一个更简单的方法
require "open3"
Open3.pipeline(
["awk '{print toupper($1)}'"],
["awk '{print tolower($1)}'"],
:in => STDIN) # this is redundant, but I might want to change :in in the future
在生产Ruby代码中使用
$stdin
和$stdout
有点不寻常,它们是受Perl启发的全局变量。大多数情况下,您会看到使用了STDIN
和STDOUT
STDOUT.put
也是冗余的,因为默认情况下put
会转到STDOUT
。好的,我可以使用STDIN
和put
,但结果是一样的。谢谢,但我确实需要使用awk。上档/下档只是一个示例,您确定需要使用awk
?Ruby没有做不到的事情,而且从awk
到Ruby的转换通常非常简单。如果您确实需要使用外部命令,是一种让您完全控制输入和输出的方法。这看起来很有趣,有没有一种方法可以组合多个命令(如上面的两个awk调用)?当然,您可以根据需要不断更改in->in,out->out,甚至在需要时嵌套它们。
puts STDIN.read.upcase.inspect
require 'open3'
Open3.popen3("awk '{print toupper($1)}'") do |cmd_in, cmd_out, cmd_err|
# Read from our STDIN and push through to the command's STDIN
cmd_in.write(STDIN.read)
# Close STDIN on the command to tell it we're finished writing.
cmd_in.close
# Read result from command's STDOUT and write to our STDOUT
puts cmd_out.read.inspect
end
require "open3"
Open3.pipeline(
["awk '{print toupper($1)}'"],
["awk '{print tolower($1)}'"],
:in => STDIN) # this is redundant, but I might want to change :in in the future