我可以像这样创建一个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
语句被忽略(但由于某种原因{ {1}}命令仍返回两行):
head
我确信有更好的方法可以做到这一点(转义awk '{print toupper($1)}' #<IO:0x007fe18406ac58> | awk '{ print tolower($1)}'
引用?)。这是我能想到的最简单的可重复的例子。在我的真实脚本中,我允许多个输入源(标准输入或文件参数)。不可协商的要求是STDIN
代码需要对输入的引用,我不能在Ruby中逐行处理它。
有什么想法吗?
更新 按照@ tadman的建议,我已经完成了这个并且它有效!:
awk
有没有办法重构这个?
答案 0 :(得分:1)
这里的问题是您直接提供$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
答案 1 :(得分:0)
好的,我找到了一种更简单的方式
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