STDIN から取得した各行に対してシェル コマンドを実行したいと思います。
この場合、 を実行したいと思いますxargs mv
。たとえば、次の 2 行があるとします。
mfoo foo
mbar bar
実行したい内容:
xargs mv mfoo foo
xargs mv mbar bar
ruby
、、awk
およびで次の戦略を試しましたxargs
。ただし、やり方が間違っています。
ただxargs
:
$ echo "mbar bar\nmbaz baz" | xargs mv
usage: mv [-f | -i | -n] [-v] source target
mv [-f | -i | -n] [-v] source ... directory
を通してawk
:
$ echo "mbar bar\nmbaz baz" | awk '{ system("xargs $0") }'
を通してruby
:
$ echo "mbar bar\nmbaz baz" | ruby -ne '`xargs mv`'
$ ls
cat foo mbar mbaz
いくつか質問があります:
- 私がやろうとしていることをどうやってやればいいのでしょうか?
- 私のそれぞれの試みの何が間違っているのでしょうか?
- 自分がやろうとしていることを「考える」ためのより良い方法はあるでしょうか?
xargs
特に、次の方法が機能するため、私の試みが機能しないことに困惑しています。
$ echo "foo\nbar" | xargs touch
$ ls
bar foo
答え1
echo "mbar bar\nmbaz baz" | xargs mv
では、何が起こっているかを確認するには オプションをxargs
使用する必要があります。上記のケースでを呼び出すと、何が表示されますか。-t
xargs
-t
mv mbar bar mbaz baz
明らかに、これは正しくありません。xargs
空腹のワニのように、パイプ経由で によって渡されたすべての引数を食べてしまったのですecho
。したがって、ワニへの引数の解放を制限する方法が必要です。また、行ごとに要求したので、POSIX オプションの-l
または が必要です。-L
echo "mbar bar\nmbaz baz" | xargs -l -t mv
POSIX 的な方法:
echo "mbar bar\nmbaz baz" | xargs -L 1 -t mv
mv mbar bar
mv mbaz baz
そしてこれがあなたが望んでいたものなのです。HTH
答え2
次の方法で行けます:
echo -e "foo bar\ndoo dar" | xargs -n 2 mv
ファイルから読み取るには:
cat lines.txt | xargs -n 2 mv
または
xargs -a lines.txt -n 2 mv
答え3
xargs
期待通りに動作しない可能性があります。この質問に対する @MichaelHomer のコメントを参照してください:
xargs mv mfoo foo
入力を待ち、入力されたmfoo foo $x_1 $x_2 $x_3...
行ごとにmv を実行します。@MichaelHomer$x_n
これは、xargs
マニュアルページ:
説明
xargs ユーティリティは、標準入力からスペース、タブ、改行、およびファイル終了で区切られた文字列を読み取り、その文字列を引数として utility を実行します。
実際には、xargs
最初の引数として指定された引数をコマンドラインユーティリティに渡すときに、改行は無視されるようです。たとえば、改行に何が起こるかに注目してください。
$ echo "foo bar\ncat dog"
foo bar
cat dog
$ echo "foo bar\ncat dog" | xargs echo
foo bar cat dog
この動作は、-n
フラグ:
-n 番号
ユーティリティの各呼び出しで標準入力から取得される引数の最大数を設定します。
前の例に戻って、xargs
引数を2つだけ取って終了したい場合は、次のようにします。@ddnomad のアプローチ:
$ echo "foo bar\ncat dog" | xargs -n 2 echo
foo bar
cat dog
また、Rakesh Sharma の回答のコメントに示されているように、BSD ではxargs
フラグを使用して読み取る行数を指定できます-L
。man ページから:
-L番号
読み取られた行数ごとにユーティリティを呼び出します。EOF に到達し、
読み取られた行数が数値より少ない場合は、利用可能な行数でユーティリティが呼び出されます。
テストには-t
スイッチも同様に役立ちます:
例をもう一度見てみると、次のどちらも機能しますが、この場合、意図していたのは 2 番目の例であるため、2 番目の例の方が適しています。
$ echo "foo bar\ncat dog" | xargs -n 2 echo
foo bar
cat dog
$ echo "foo bar\ncat dog" | xargs -L 1 echo
foo bar
cat dog
man ページからの注記:
-L オプションと -n オプションは相互に排他的であり、最後に指定されたオプションが使用されます。
答え4
xargs を使用しない非常に簡単な解決策があります。
次の関数を定義します。
$ mv2() { while (($# >1 )); do echo mv "$1" "$2"; shift 2; done; }
次に、必要なファイル名のリストを指定して呼び出します (改行は不要)。
$ mv2 mbar bar mbaz baz
mv mbar bar
mv mbaz baz
関数を実際に動作させるには、エコーを削除します。