1

Popen3 を使用していくつかの Perl スクリプトを実行し、その出力をテキスト ファイルにダンプしています。テキスト ファイル内で、Perl スクリプトの結果を検索します。約 40 分間 (約 220 ファイル) 実行した後にエラーが発生します。

ruby/1.8/open3.rb:49:in `pipe': Too many open files (Errno::EMFILE)
    from /ruby/1.8/open3.rb:49:in `popen3'
    from ./RunAtfs.rb:9
    from ./RunAtfs.rb:8:in `glob'
    from ./RunAtfs.rb:8

スクリプトは以下です。

require 'logger'
require 'open3'
atfFolder = ARGV[0]
testResult = ARGV[1]
res = "result.txt"
open('result.txt', 'w') { }
Dir.glob(atfFolder+'/*.pl') do |atfTest|
 Open3.popen3("atf.pl -c run-config.pl -t #{atfTest}") do |i, o, e, t|
   while line = e.gets
     $testFile = testResult + line[/^[0-9]+$/].to_s + "testOutput.txt"
      log = Logger.new($testFile)
      log.info(line)
      end
    log.close
end
 lastLine = `tail +1 #{$testFile}`
 file = File.open(res, 'a')
 if(lastLine.include? "(PASSED)")
    file.puts("Test #{atfTest} --> Passed")
    file.close
    File.delete($testFile)
 else
    file.puts("Test #{atfTest} --> Failed!")
    file.close
 end
end

popen3このスクリプトは 4900 個の Perl ファイルを処理しているため、ファイルが多すぎるのか、正しく使用していないのかわかりません。

私を助けてくれてありがとう!

いくつかの非常に役立つポインタの後に、スクリプトをリファクタリングしました! コードはうまく機能しています!

require 'open3'

atf_folder, test_result = ARGV[0, 2]
File.open('result.txt', 'w') do |file| end

Dir.glob("#{ atf_folder }/*.pl") do |atf_test|

test_file = atf_test[/\/\w+.\./][1..-2].to_s + ".txt"
comp_test_path = test_result + test_file
File.open(comp_test_path, 'w') do |file| end

Open3.popen3("atf.pl -c run-config.pl -t #{ atf_test }") do |i, o, e, t|

    while line = e.gets

      File.open(comp_test_path, 'a') do |file|
        file.puts(line)
      end
    end
end

last_line = `tail +1 #{comp_test_path}`
File.open('result.txt', 'a') do |file|

    output_str = if (last_line.include? "(PASSED)")

    File.delete(comp_test_path)

    "Passed"

    else

    "Failed!"

end

file.puts "Test #{ atf_test } --> #{ output_str }"

end
end
4

1 に答える 1

1

このことを考慮:

require 'logger'
require 'open3'

atf_folder, test_result = ARGV[0, 2]

Dir.glob("#{ atf_folder }/*.pl") do |atf_test|

  Open3.popen3("atf.pl -c run-config.pl -t #{ atf_test }") do |i, o, e, t|

    while line = e.gets
      $testFile = test_result + line[/^[0-9]+$/].to_s + "testOutput.txt"
      log = Logger.new($testFile)
      log.info(line)
      log.close
    end

  end

  lastLine = `tail +1 #{ $testFile }`
  File.open('result.txt', 'a') do |file|

    output_str = if (lastLine.include? "(PASSED)")

                  File.delete($testFile)

                  "Passed"

                else

                  "Failed!"

                end

    file.puts "Test #{ atf_test } --> #{ output_str }"

  end

end

もちろん、サンプル データがないのでテストはされていませんが、Ruby 向けにもっと奇妙に書かれています。

注意事項:

  • atf_folder, test_result = ARGV[0, 2]ARGV 配列をスライスし、並列代入を使用して両方のパラメーターを一度に取得します。それらの値を取得したことを確認するためにテストする必要があります。また、より複雑なスクリプトに移行する場合は、Ruby の STDLIB に含まれるOptionParserクラスを利用してください。
  • Ruby では、ブロックを に渡すことができますFile.open。これにより、ブロックが終了するとファイルが自動的に閉じられます。これは Ruby の大きな強みであり、ご覧のようなエラーを減らすのに役立ちます。Loggerはそうしないので、あなたがやっているようにファイルハンドルがぶら下がったままにならないように特別な注意を払う必要があります。代わりに、次を使用します。

      log = Logger.new($testFile)
      log.info(line)
      log.close
    

    すぐにハンドルを閉じます。ループ内ではなくループ外で実行しているため、開いているハンドルがたくさんあります。

    また、Logger が必要かどうか、または通常のものFile.openで十分かどうかも検討してください。ロガーには追加のオーバーヘッドがあります。

  • の使用に$testFileは疑問があります。$variablesはグローバルであり、それらの使用は通常、少なくとも使用する理由とタイミングを理解するまでは、何か間違っていることを示しています。それを使用してコードをリファクタリングします。
  • Ruby では変数やメソッドはクラスやモジュールに使われる CamelCase ではなく、snake_case です。CodeDoingTheWrongThing を実行してそれを読むまでは、それほど多くないように思えます。(キャメルケースを解読するのに、あなたの脳がどのように行き詰まったかに注意してください?)

一般に、これがあなたが望むことを行うための最速の方法であるかどうかは疑問です. greporを使用してシェル スクリプトを記述できるのではないかtailと思います。システム管理者と一緒に座って、ブレインピッキングを行うかもしれません。

于 2013-10-15T00:34:11.203 に答える