Javaコマンドを_ls | grep pattern -
_の一致ごとに1回実行したい。この場合、_find pattern -exec Java MyProg '{}' \;
_を実行できると思うが、一般的なケースに興味がある-「標準入力のすべての行に対して1回コマンドを実行する」という簡単な方法はありますか?(fishまたはbashで)。
それがxargs
が行うことです。
... | xargs command
受け入れられた答え は正しい考えを持っていますが、鍵はxargs
を渡すことです-n1
スイッチ。これは、「出力行ごとにコマンドを1回実行する:」という意味です。
cat file... | xargs -n1 command
または、単一の入力ファイルの場合は、cat
からのパイプを完全に回避して、次のようにすることができます。
<file xargs -n1 command
Bashまたはその他のBourneスタイルのシェル(ash、ksh、zshなど)では:
while read -r line; do command "$line"; done
read -r
は、標準入力から1行を読み取ります(-r
なしのread
は、バックスラッシュを解釈します。これは望ましくありません)。したがって、次のいずれかを実行できます。
$ command | while read -r line; do command "$line"; done
$ while read -r line; do command "$line"; done <file
私はキースに同意します。xargsはこの仕事のための最も一般的なツールです。
私は通常、3ステップのアプローチを使用します。
小さくて速い方法がありますが、この方法はほとんど常に機能します。
簡単な例:
ls |
grep xls |
awk '{print "MyJavaProg --arg1 42 --arg2 "$1"\0"}' |
xargs -0 bash -c
最初の2行は操作するファイルをいくつか選択し、awkは実行するコマンドといくつかの引数を含むNice文字列を準備します。$ 1はパイプからの最初の列の入力です。そして最後に、xargsがこの文字列をbashに送信して、それを実行することを確認します。
少しやり過ぎですが、このレシピは非常に柔軟なので、多くの場所で私を助けてくれました。
GNU Parallelはそのようなタスクのために作られています。最も簡単な使用法は次のとおりです。
cat stuff | grep pattern | parallel Java MyProg
詳細については、紹介動画をご覧ください: http://www.youtube.com/watch?v=OpaiGYxkSuQ
また、while read
フィッシュシェルでループします( fish タグを使用していることを考えると、フィッシュシェルが必要だと思います)。
command | while read line
command $line
end
注意すべきいくつかのポイント。
read
はかかりません-r
引数。最も一般的な使用例を簡単にするために、バックスラッシュを解釈しません。$line
、bashとは異なり、fishは変数をスペースで区切りません。command
自体は構文エラーです(このようなプレースホルダー引数の使用をキャッチするため)。実際のコマンドに置き換えてください。潜在的にサニタイズされていない入力を処理する場合、実行する前に、ジョブ全体を1行ずつ「スペルアウト」して視覚的に確認したいと思います(特に、メールボックスのクリーニングなどの破壊的な場合)。
したがって、私が行うことは、パラメーター(つまり、ユーザー名)のリストを生成し、次のように、1行に1レコードの方法でファイルにフィードします。
johndoe
jamessmith
janebrown
次に、vim
でリストを開き、次のように、実行する必要のある完全なコマンドのリストが表示されるまで、検索式と置換式でリストをマングルします。
/bin/rm -fr /home/johndoe
/bin/rm -fr /home/jamessmith
このように、正規表現が不完全な場合、どのコマンドで潜在的な問題があるかがわかります(つまり、/bin/rm -fr johnnyo connor
)。このようにして正規表現を元に戻し、より信頼性の高いバージョンで再試行できます。名前のマングリングは、ヴァンゴッホ、オコナーズ、セントクレア、スミスウェッソンなどのすべてのエッジケースを処理するのが難しいため、このことで悪名高くなっています。
set hlsearch
はvim
でこれを行うのに役立ちます。これは、すべての一致を強調表示するため、一致しない場合、または意図しない方法で一致する場合に簡単に見つけることができます。
あなたの正規表現が完璧であり、あなたがテストする/考えることができるすべてのケースを捕らえたら、私は通常それをsed式に変換して、別の実行のために完全に自動化できるようにします。
入力の行数が原因で目視による検査ができない場合は、実行する前にコマンドを画面にエコーすることを強くお勧めします(さらに良いのはログ)。エラーが発生した場合は、どのコマンドが原因であるかを正確に把握できます。失敗する。その後、元の正規表現に戻ってもう一度調整できます。
ここで、すぐに使用できるコピーペースト:
cat list.txt | xargs -I{} command parameter {} parameter
リストの項目は{}がある場所に配置され、残りのコマンドとパラメーターはそのまま使用されます。
他の答えが示すように、これはxargs
で可能です。質問の「1行に1回」の部分で2つの詳細を区別する必要があります。
-n 1
を使用すると、各引数に対してコマンドが1回だけ呼び出されるようになります。ただし、デフォルトでは、xargs
は引数がスペースで区切られていると想定します。これは、ファイルにスペースが含まれると中断します。-d '\n'
を使用するか、tr '\n' '\0'
で入力を前処理して-0
を使用します。これにより、コマンドは入力のスペースに対して堅牢になります。最終的なコマンドラインは次のようになります。
.... | xargs -n 1 -d '\n' <command>
または(tr
を使用)
.... | tr '\n' '\0' | xargs -n 1 -0 <command>
コマンドが一度に複数の引数を処理できる場合(grep
またはsed
など)、-n 1
を省略して、多くの場合、操作を高速化できます。
プログラムがパイプを無視するが、ファイルを引数として受け入れる場合は、それを特殊ファイル/dev/stdin
に指定するだけです。
私はJavaに精通していませんが、bashでこれを行う方法の例を次に示します。
$ echo $'pwd \n cd / \n pwd' |bash /dev/stdin
/home/rolf
/
$は、bashが\n
を改行に変換するために必要です。理由はわかりません。
私はこれを好みます-複数行のコマンドと明確なコードを許可します
find -type f -name filenam-pattern* | while read -r F
do
echo $F
cat $F | grep 'some text'
done