web-dev-qa-db-ja.com

単一のコマンドでサブディレクトリ内のファイルを見つけてファイル名で並べ替える方法は?

find . ! -path "./build*" -name "*.txt"を使用した通常の検索の結果:

./tool/001-sub.txt
./tool/000-main.txt
./zo/001-int.txt
./zo/id/002-and.txt
./as/002-mod.txt

sort -nでソートした場合:

./as/002-mod.txt
./tool/000-main.txt
./tool/001-sub.txt
./zo/001-int.txt
./zo/id/002-and.txt

ただし、望ましい出力は次のとおりです。

./tool/000-main.txt
./zo/001-int.txt
./tool/001-sub.txt
./zo/id/002-and.txt
./as/002-mod.txt

つまり、出力はファイル名のみに基づいてソートされますが、フォルダー情報は出力の一部として維持する必要があります。

編集:サブディレクトリ構造に複数のレベルが含まれる場合があるため、例をより複雑にします。

9
unode

最後のフィールドで並べ替える必要があります(フィールド区切り記号として/を考慮)。残念ながら、フィールド数が変化したときにこれを行うことができるツールは考えられません(sort -kだけが負の値を取ることができる場合)。

これを回避するには、装飾、ソート、デコレートを行う必要があります。つまり、ファイル名を取得して、最初に配置し、その後にフィールドセパレータを配置してから、並べ替えを実行してから、最初の列とフィールドセパレータを削除します。

find . ! -path "./build*" -name "*.txt" |\
    awk -vFS=/ -vOFS=/ '{ print $NF,$0 }' |\
    sort -n -t / |\
    cut -f2- -d/

そのawkコマンドはフィールドセパレーターFS/に設定されていると言います。これは、フィールドの読み取り方法に影響します。 出力フィールド区切り文字OFS/に設定されます。これは、レコードの印刷方法に影響します。次のステートメントは、最後の列(NFはレコード内のフィールド数なので、たまたま最後のフィールドのインデックスでもあります)だけでなく、レコード全体($0は全記録);それらの間のOFSでそれらを印刷します。次に、リストはsortedになり、/をフィールド区切り文字として扱います。レコードの最初にファイル名があるため、それによってソートされます。次に、cutはフィールド2から最後までのみを出力し、/をフィールド区切り文字として扱います。

9
Shawn J. Goff

最後の手順では、ファイル '-printf'を使用して名前とパスを出力し、名前で並べ替え、名前を切り捨てます。 '###'は単なるマーカーで、切り取りに役立ちます。

find -name "*.txt" -printf "%f###%p\n" | sort -n | sed 's/.*###//'

%fはファイル名を、%pはパス全体を出力します。

Findコマンドを簡略化して1行にまとめましたが、もちろん! -path "./build*"部分。

4
user unknown

Zsh≥4.3.10の場合:

print -l -- **/*.txt~build*(oe\''REPLY=${REPLY:t}'\')
  • **/*.txtは、現在のディレクトリとそのサブディレクトリの*.txtと一致します 再帰的に
  • ~build*excludes は、build*で始まるテキスト(! -path './build*'など)に一致します。 (最初にsetopt extended_globが必要です。)
  • (oe\''…'\')はソート glob qualifier です。 REPLY=…は、返す文字列からソートする文字列を作成します。
  • ${REPLY:t}は、パスの basename (“ tail”)です。