6

stdout と stderr の出力を処理しながら、シェル スクリプトを実行したいと考えています。現在、stdin、stdout、stderr のProcess.run、 with 、および 3 つのパイプを使用してコマンドを実行しています。shell=falsestdout と stderr から読み取り、出力をログに記録 (またはその他の方法で処理) するファイバーを生成します。これは、個々のコマンドではうまく機能しますが、スクリプトではひどく失敗します。

shell=trueを呼び出すときに簡単に設定できますProcess.runが、Crystal ソースを見ると、コマンドラインの先頭に「sh」を追加するだけのようです。「bash」を先頭に追加しようとしましたが、役に立ちませんでした。

リダイレクト ( >file) やパイプ (例curl something | bash) のようなものは動作しないようですProcess.run

たとえば、シェルスクリプトをダウンロードして実行するには、次のことを試しました。

cmd = %{bash -c "curl http://dist.crystal-lang.org/apt/setup.sh " | バッシュ}

Process.run(cmd, ...)

イニシャルbashは、パイプ オペレーターを有効にすることを期待して追加されました。役に立たないようです。また、各コマンドを個別に実行してみました:

script.split("\n").reject(/^#/, "").each { Process.run(...) }

しかしもちろん、コマンドがリダイレクトやパイプを使用している場合は失敗します。たとえば、コマンドecho "deb http://dist.crystal-lang.org/apt crystal main" >/etc/apt/sources.list.d/crystal.listは単純に次のように出力します。

"deb http://dist.crystal-lang.org/apt crystal main" >/etc/apt/sources.list.d/crystal.list`

``代わりにバックティックの実行方法を使用するとうまくいくかもしれません。しかし、そうすると、出力をリアルタイムでキャプチャすることができなくなります。

4

3 に答える 3

12

問題は UNIX の問題です。親プロセスは、子プロセスの STDOUT にアクセスできる必要があります。| bashパイプを使用して、だけでなくを含むコマンド全体を実行するシェル プロセスを開始する必要がありますcurl $URL。クリスタルでは、これは次のとおりです。

command = "curl http://dist.crystal-lang.org/apt/setup.sh | bash"
io = MemoryIO.new
Process.run(command, shell: true, output: io)
output = io.to_s

または、Crystal の機能を複製したい場合は、次のようにします。

Process.run("sh", {"-c", command}, output: io)
于 2016-02-18T19:39:54.260 に答える
5

ファイルのソースコードを読むことに基づいて理解していrun.crます。コマンドと引数の処理方法は、他の言語と非常によく似ています。

がないshell=true場合、 のデフォルトの動作は、実行Process.runする実行可能ファイルとしてコマンドを使用することです。これは、文字列が引数なしのプログラム名である必要があることを意味します。たとえば、私のシステムにはで呼び出されるプログラムがあるため、有効な名前になります。unameuname/usr/bin

%{bash -c "echo hello world"}を使用して正常に動作したことがある場合は、何かが間違っています。デフォルトの動作は、どのシステムにも存在する可能性が低いshell=falseというプログラムを実行しようとするはずです。bash -c "echo hello world"

「shell=true」を渡すと、コマンドのsh -c <command>ような文字列が機能するようになります。echo hello worldこれにより、リダイレクトとパイプラインも機能します。

このshell=true動作は、通常、次のように解釈できます。

cmd = "sh"
args = [] of String
args << "-c" << "curl http://dist.crystal-lang.org/apt/setup.sh | bash"
Process.run(cmd, args, …)

ここでは引数の配列を使用していることに注意してください。引数の配列がないと、引数がシェルに渡される方法を制御できません。

最初のバージョンの有無にかかわらずshell=true機能しない理由は、パイプラインがbash に送信するコマンドである のにあるためです。-c

于 2016-02-18T17:20:07.557 に答える