web-dev-qa-db-ja.com

xargs -0の後に複数のコマンドを実行する方法は?

find . -name "filename including space" -print0 | xargs -0 ls -aldF > log.txt
find . -name "filename including space" -print0 | xargs -0 rm -rdf

これらの2つのコマンドを1つに組み合わせて、2つではなく1つの検索のみを実行することは可能ですか?

私はxargsを知っています-スペースを含むファイル名を処理するときにエラーを引き起こす可能性のある方法があるかもしれません。どんなガイダンスも大歓迎です。

24
Richard Chen

findを複数回実行しないようにする場合は、teeの直後にfindを実行して、find出力をファイル、次のように行を実行します。

find . -name "filename including space" -print0 | tee my_teed_file | xargs -0 ls -aldF > log.txt
cat my_teed_file | xargs -0 rm -rdf 

これと同じことを達成する別の方法(実際に達成したい場合)は、findの出力を変数に格納することです(TBでない場合)データの):

founddata=`find . -name "filename including space" -print0`
echo "$founddata" | xargs -0 ls -aldF > log.txt
echo "$founddata" | xargs -0 rm -rdf
16
Jonathan M
find . -name "filename including space" -print0 | 
  xargs -0 -I '{}' sh -c 'ls -aldF {} >> log.txt; rm -rdf {}'
48
glenn jackman

私はこれらのすべての答えがこの問題を解決する正しい方法を示していると信じています。そして、私はJonathanとGlennの方法の2つのソリューションを試してみました。これらはすべて、私のMac OS Xではうまく機能しました。mouvicielの方法は、おそらくいくつかの構成上の理由により、私のOSでは機能しませんでした。そして、それはジョナサンの2番目の方法に似ていると思います(私は間違っているかもしれません)。

グレンの方法へのコメントで述べたように、少しの微調整が必​​要です。だからここに私が試したコマンドが完璧に機能しました:

find . -name "filename including space" -print0 | 
xargs -0 -I '{}' sh -c 'ls -aldF {} | tee -a log.txt ; rm -rdf {}'

またはGlennの提案どおり:

find . -name "filename including space" -print0 | 
xargs -0 -I '{}' sh -c 'ls -aldF {} >> log.txt ; rm -rdf {}'
5
Richard Chen

ファイル名に改行がない限り、GNU Parallelに-print0は必要ありません。

find . -name "My brother's 12\" records" | parallel ls {}\; rm -rdf {} >log.txt

詳細については、紹介動画をご覧ください: http://www.youtube.com/watch?v=OpaiGYxkSuQ

4
Ole Tange

恐ろしいxargsアプローチのバリエーションだけで-print0およびxargs -0、これは私がそれを行う方法です:

ls -1 *.txt  | xargs --delimiter "\n" --max-args 1 --replace={} sh -c 'cat {}; echo "\n"'

脚注:

  • はい私は改行がファイル名に現れることができることを知っていますが、彼らの正しい心の誰がそれをするでしょう
  • xargsには短いオプションがありますが、読者の理解のために長いオプションを使用しました。
  • 私は使うだろう ls -1再帰しない動作が必要な場合find -maxdepth 1 -iname "*.txt"これはもう少し冗長です。
2

私はパーティーに遅れましたが、ここで取り上げられなかったもう1つの解決策があります。ユーザー定義関数です。 1行に複数の命令を置くのは扱いにくく、読みにくく、保守が難しい場合があります。上記のforループはそれを回避しますが、コマンドラインの長さを超える可能性があります。

ここに別の方法があります(テストされていません)。

function processFiles {
  ls -aldF "$@"
  rm -rdf "$@"
}
export -f processFiles

find . -name "filename including space"` -print0 \
  | xargs -0 bash -c processFiles dummyArg > log.txt

これは、私に多くの悲しみを与えた "dummyArg"を除いて、非常に簡単です。この方法でbashを実行すると、引数が読み込まれます

"$0" "$1" "$2"  ....

期待の代わりに

"$1" "$2" "$3"    ....

ProcessFiles {}は最初の引数が "$ 1"であると想定しているため、ダミー値を "$ 0"に挿入する必要があります。

Footnontes:

  1. 私はbash構文のいくつかの要素(例: "export -f")を使用していますが、これは他のシェルに適応すると信じています。
  2. 私が初めてこれを試したとき、私は仮引数を追加しませんでした。代わりに、関数内の引数行に "$"を追加しました(例ls -aldf "$ 0" "$ @")。悪いアイデア。文体の問題は別として、 "find"コマンドが何も返さない場合は、問題が発生します。その場合、$ 0は「bash」に設定されます。代わりにダミー引数を使用すると、このすべてが回避されます。
1
Phil Freed

findの代わりにforを使用すると、xargsの後に複数のコマンドを実行できます。

IFS=$'\n'
for F in `find . -name "filename including space"`
do
    ls -aldF $F > log.txt
    rm -rdf $F
done

IFSは内部フィールド区切り文字を定義します。デフォルトは<space> <tab> <newline>です。ファイル名にスペースが含まれている可能性がある場合は、上記のように再定義することをお勧めします。

1
ericbn

別の解決策:

find . -name "filename including space" -print0 \
| xargs -0 -I FOUND echo "$(ls -aldF FOUND > log.txt ; rm -rdf FOUND)"
0
mouviciel