web-dev-qa-db-ja.com

現在のシェル内でコマンドの出力を実行する方法は?

source(別名.)ユーティリティをよく知っています。このユーティリティは、ファイルからコンテンツを取得し、現在のシェル内で実行します。

今、私は次のようにいくつかのテキストをシェルコマンドに変換してから実行しています:

$ ls | sed ... | sh

lsは単なるランダムな例であり、元のテキストは何でもかまいません。 sedも、テキストを変換するための単なる例です。興味深いのはshです。 shに送ったものは何でもパイプして実行します。

私の問題は、新しいサブシェルを開始することを意味します。現在のシェル内でコマンドを実行したいです。テキストファイルにコマンドがある場合、source some-fileでできるようになります。

一時ファイルを作成したくないのは、汚いからです。

または、現在のシェルとまったく同じ特性でサブシェルを起動したいと思います。

更新

バックティックを使用したソリューションは確かに機能しますが、出力を確認して変更しているときに頻繁にこれを行う必要があるため、結果を最終的に何かにパイプする方法があればはるかに好まれます。

悲しい更新

ああ、/dev/stdinの物はとてもきれいに見えましたが、より複雑なケースでは機能しませんでした。

だから、私はこれを持っています:

find . -type f -iname '*.doc' | ack -v '\.doc$' | Perl -pe 's/^((.*)\.doc)$/git mv -f $1 $2.doc/i' | source /dev/stdin

これにより、すべての.docファイルの拡張子が小文字になります。

ちなみに、これはxargsで処理できますが、それは重要ではありません。

find . -type f -iname '*.doc' | ack -v '\.doc$' | Perl -pe 's/^((.*)\.doc)$/$1 $2.doc/i' | xargs -L1 git mv

したがって、前者を実行するとすぐに終了し、何も起こりません。

77
kch
$ ls | sed ... | source /dev/stdin

UPDATE:これは、bash 4.0、tcsh、およびダッシュで動作します(source.に変更した場合) 。どうやらこれはbash 3.2ではバグがあったようです。 bash 4.0リリースノート から:

`。 'の原因となったバグを修正しましたデバイスや名前付きパイプなどの非正規ファイルからのコマンドの読み取りと実行に失敗する。

80
mark4o

evalコマンドは、まさにこの目的のために存在しています。

eval "$( ls | sed... )"

bash manual からの詳細:

eval

          eval [arguments]

引数は単一のコマンドに連結され、その後読み取られて実行され、その終了ステータスがevalの終了ステータスとして返されます。引数がない場合、または空の引数のみがある場合、戻りステータスはゼロです。

116
Juliano

うわー、これは古い質問であることは知っていますが、最近、まったく同じ問題を抱えていることに気付きました(これが私がここに来た理由です)。

とにかく-私はsource /dev/stdin答えますが、私はより良いものを見つけたと思います。実際には一見シンプルです:

echo ls -la | xargs xargs

いいですね実際には、複数の行がある場合、各コマンドを個別に実行するのではなく、それらを単一のコマンドに連結するため、これはまだ必要なことを行いません。だから私が見つけた解決策は次のとおりです:

ls | ... | xargs -L 1 xargs

-L 1オプションは、コマンド実行ごとに(最大)1行を使用することを意味します。 注:行の末尾がスペースの場合、次の行と連結されます!そのため、各行がスペース以外で終わっていることを確認してください。

最後に、あなたができる

ls | ... | xargs -L 1 xargs -t

実行されるコマンドを確認します(-tは冗長です)。

誰かがこれを読んでくれることを願っています!

36
rabensky

process substitution を使用してみてください。これは、コマンドの出力を一時ファイルに置き換えた後、そのファイルを取得できます。

source <(echo id)
27
rishta

これは質問に対する「正しい答え」だと思います。

ls | sed ... | while read line; do $line; done

つまり、whileループにパイプできます。 readコマンドコマンドは、そのstdinから1行を取得し、変数$lineに割り当てます。 $lineは、ループ内で実行されるコマンドになります。そして、入力にさらに行がなくなるまで続けます。

これは、一部の制御構造(別のループなど)ではまだ機能しませんが、この場合の法案に適合します。

6
Geoff Nixon
`ls | sed ...`

ls | sed ... | source -はきれいになりますが、残念ながらsource-stdinを意味します。

5
chaos

あなたの解決策は、逆ティックを使用したコマンド置換であると思います: http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html

セクション3.4.5を参照してください

1
Eric Wendelin

Bash 3.2(macos)でmark4oのソリューションを使用するには、この例のようなパイプラインの代わりにhere文字列を使用できます。

. /dev/stdin <<< "$(grep '^alias' ~/.profile)"
0
ish-west

なぜsourceを使用しないのですか?

$ ls | sed ... > out.sh ; source out.sh
0
Kaleb Pederson