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
つまり、出力はファイル名のみに基づいてソートされますが、フォルダー情報は出力の一部として維持する必要があります。
編集:サブディレクトリ構造に複数のレベルが含まれる場合があるため、例をより複雑にします。
最後のフィールドで並べ替える必要があります(フィールド区切り記号として/
を考慮)。残念ながら、フィールド数が変化したときにこれを行うことができるツールは考えられません(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でそれらを印刷します。次に、リストはsort
edになり、/
をフィールド区切り文字として扱います。レコードの最初にファイル名があるため、それによってソートされます。次に、cut
はフィールド2から最後までのみを出力し、/
をフィールド区切り文字として扱います。
最後の手順では、ファイル '-printf'を使用して名前とパスを出力し、名前で並べ替え、名前を切り捨てます。 '###'は単なるマーカーで、切り取りに役立ちます。
find -name "*.txt" -printf "%f###%p\n" | sort -n | sed 's/.*###//'
%fはファイル名を、%pはパス全体を出力します。
Findコマンドを簡略化して1行にまとめましたが、もちろん! -path "./build*"
部分。
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”)です。