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

4

6 に答える 6

3

グロブは辞書式順序で展開されることが保証されています。

for dir in ./*/
do
    files=($dir/*)           # create an array
    echo "${files[@]: -1}"   # access its last member
done
于 2012-06-22T14:42:59.997 に答える
2

テスト済み:

find . -type d -name '*.res' | while read dir; do
    find "$dir" -maxdepth 1 | sort -n | tail -n 1
done
于 2012-06-22T14:29:56.517 に答える
2

使用するのはawkどうですか?あなたは本当に簡単に最初の出現を得ることができます:

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

最後のオカレンスを取得するには、いくつかの種類をパイプでつなぐことができます。

[ghoti@pc ~]$ 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
[ghoti@pc ~]$ 

「find」と「grep」を使用している場合、おそらくこれを行うことができます。

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

これはどのように作動しますか?

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

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

  • a[$2] {next}a-添え字が$2の配列(つまり「/ 501」)が存在する場合は、次の行にジャンプします。さもないと...
  • {a[$2]=1}-配列に添え字$2を1に設定します。これにより、将来、最初の条件がtrueと評価され、次に...
  • 1-行を印刷します。

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

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

アップデート

デニスの賢明なアドバイスによると、上記に含めたawkスクリプトは、次のように変更することで改善できます。

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

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

これは機能的には同じですが、配列メンバーに値を割り当てるのではなく、配列メンバーを定義するだけでよいという利点があります。これにより、awkの実装によってはメモリやCPUを節約できます。とにかく、それはよりきれいです。

于 2012-06-22T14:30:34.460 に答える
1

私はこのような何かを思いついた:

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

多分それはもっと簡単かもしれません

于 2012-06-22T14:29:29.193 に答える
0

find内からシェルを呼び出すことがオプションである場合は、これを試してください

  find * -type d -exec sh -c "echo -n './'; ls -1 {}/*.bin | sort -n -r | head -n 1" \;
于 2012-06-22T14:38:24.023 に答える
0

そしてここに1つのライナーがあります

find . -mindepth 1 -type d | sort | sed -e "s/.*/ls & | sort | tail -n 1 | xargs -I{} echo &\/{}/" | bash
于 2012-06-22T14:45:44.977 に答える