我可以創建一個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