2012-06-22 10 views
7

私はこの最高の番号を持つ各ディレクトリのファイルをファイル名として見つけるには?

./501.res/1.bin 
./503.res/1.bin 
./503.res/2.bin 
./504.res/1.bin 

のようなファイル構造を持っていると私は、ファイル名として、最も高い番号を持つ各ディレクトリ内.binファイルへのファイルパスを見つけるしたいと思います。だから私は探しています出力は

./501.res/1.bin 
./503.res/2.bin 
./504.res/1.bin 

だろうファイルを持つことができる最大数は9

質問

私はBASHであることをどのように行うのですかですか?

私はこのようないろいろ書い思い付いた限りfind .|grep bin|sort

答えて

1

何についてawkを使用していますか?あなたは本当に、単にFIRST発生を得ることができます:あなたは「グレップ」を「見つける」使用としていることを考えると

[[email protected] ~]$ sort -r data1 | awk 'BEGIN{FS="."} a[$2] {next} {a[$2]=1} 1' | sort 
./501.res/1.bin 
./503.res/2.bin 
./504.res/1.bin 
[[email protected] ~]$ 

[[email protected] ~]$ cat data1 
./501.res/1.bin 
./503.res/1.bin 
./503.res/2.bin 
./504.res/1.bin 
[[email protected] ~]$ awk 'BEGIN{FS="."} a[$2] {next} {a[$2]=1} 1' data1 
./501.res/1.bin 
./503.res/1.bin 
./504.res/1.bin 
[[email protected] ~]$ 

は、ある種のカップルを通してあなたがパイプをできた最後の出現を取得するにはおそらくこれを行うことができます:

find . -name \*.bin -type f -print | sort -r | awk 'BEGIN{FS="."} a[$2] {next} {a[$2]=1} 1' | sort 

これはどのように機能しますか?

findコマンドはグロブであなたのファイルを選択する機能など、多くの便利なオプションがあり、ファイルの種類を選択するには、などがその出力あなたが既に知っている、そしてそれはsort -rへの入力になります。

まず、入力データを逆順に並べ替えます(sort -r)。これにより、任意のディレクトリ内で、最も番号の付いたファイルが最初に表示されることが保証されます。その結果はawkに送られます。 FSはフィールド区切り文字で、$2を "/ 501"、 "/ 502"などに変換します。Awkスクリプトのセクションはcondition {action}という形式のセクションがあり、入力の各行ごとに評価されます。条件がない場合、アクションはすべての行で実行されます。 "1"が条件であり、アクションがない場合は、行を出力します。次のようにこのスクリプトが実行壊れている:

  • a[$2] {next} - 添字$ 2(すなわち、「/ 501」)が存在する、との配列aだけで次の行にジャンプします。そうでなければ...
  • {a[$2]=1}は - 行を印刷する - 将来的には最初の条件が真と評価されますように、そして...
  • 1、1に配列に添字$ 2セット。

このawkスクリプトの出力は、必要なデータですが、逆の順序です。最終的にsortは、あなたが期待する順番に物事を戻します。

今、パイプの数が多いので、何百万行もの入力を同時に処理するように頼んだら、ソートは少しでもリソースが空いている可能性があります。このソリューションは、ファイル数が少ない場合は完全に十分ですが、大量の入力を処理している場合はお知らせください。オールインワンawkソリューションを考え出すことができます(これは60秒以上かかる場合があります書き込む)。

UPDATE

これは機能的に同じですがパーデニスの賢者の助言、私は上記に含まawkスクリプトが

BEGIN{FS="."} $2 in a {next} {a[$2]} 1 

BEGIN{FS="."} a[$2] {next} {a[$2]=1} 1 

からそれを変更することで改善することができました利点は、値を代入するのではなく配列メンバを定義するだけで、メモリやCPUを節約できますあなたのawkの実装が保留中です。とにかく、それはきれいです。

+0

'{next {}}で$ 2を使って配列に要素の存在をテストする方が良いです。このようにすると、単に新しい配列要素を参照するだけで新しい配列要素が作成されるわけではありません。これは私がこれについて議論していた頃のことです。ちなみに、 'のように'を使うと、 '{a [$ 2] = 1}'の代わりに '{a [$ 2]}'を使うことができますが、どちらでも動作します。 –

+0

@DennisWilliamson、AH、先日、あなたが得ていたことを理解しました。ポインタに感謝します。 :) – ghoti

0

として来ている:

for dir in $(find . -mindepth 1 -type d | sort); do 
    file=$(ls "$dir" | sort | tail -n 1); 
    [ -n "$file" ] && (echo "$dir/$file"); 
done 

多分それはテスト済み

+0

である私は、ナンバリングはおそらく9 – bcelary

+0

@bcelaryより高くなるようソート-n持つべきだと思う - 述べOP *「最高数のファイル缶持っているのは9です "* – ghoti

+0

ああ - 申し訳ありません。通知に失敗しました: – bcelary

2

シンプルにすることができます

find . -type d -name '*.res' | while read dir; do 
    find "$dir" -maxdepth 1 | sort -n | tail -n 1 
done 
+1

パスを表示しません。 – jcubic

+0

修正しました。 find ... -maxdepth 1は現在のパスを正しく示しています。ありがとう。 – bcelary

0

検索内からシェルを起動すると、オプションで、この

find * -type d -exec sh -c "echo -n './'; ls -1 {}/*.bin | sort -n -r | head -n 1" \; 
3

グロブを辞書順に展開されることが保証されてみている場合。

for dir in ./*/ 
do 
    files=($dir/*)   # create an array 
    echo "${files[@]: -1}" # access its last member 
done 
0

そして、ここで1つのライナー

find . -mindepth 1 -type d | sort | sed -e "s/.*/ls & | sort | tail -n 1 | xargs -I{} echo &\/{}/" | bash 
関連する問題