複数列のアルファベットと数字の並べ替え

複数列のアルファベットと数字の並べ替え

並べ替えたい

  1. ファイル名に基づいています。
  2. ファイル名の接頭辞が一致し、ファイルが数字で終わる場合は、ファイル名の末尾の数字に基づいて数字でソートしたいと思います。

次のような

cat /tmp/foo.txt | sort -t/ -k3,3 -k3,3n

1は完成しましたが、2は完成できませんでした。

入力する/tmp/foo.txt

dirA/catA/apple.txt
dirA/catA/addition.txt
dirA/catA/difference
dirA/catB/binary.txt
dirA/catB/carry.txt
dirA/catB/digit
dirA/catC/test-10.txt
dirA/catC/test-100.txt
dirA/catC/test-1000.txt
dirA/catC/test-11.txt
dirA/catC/test-2.txt
dirA/catC/test-20.txt
dirA/catC/test-25.txt
dirA/catC/test-5.txt
dirA/catC/test-50.txt
dirA/catC/test-500.txt
dirA/catC/test-7.txt
dirA/catC/test-75.txt
dirA/catC/test-8.txt
dirA/catC/abc-test-9.txt
dirA/catC/abc-test-999.txt
dirA/catC/abc-test-75.txt
dirA/catC/abc-test-8.txt

希望の出力

dirA/catC/abc-test-8.txt
dirA/catC/abc-test-9.txt
dirA/catC/abc-test-75.txt
dirA/catC/abc-test-999.txt
dirA/catA/addition.txt
dirA/catA/apple.txt
dirA/catB/binary.txt
dirA/catB/carry.txt
dirA/catA/difference
dirA/catB/digit
dirA/catC/test-2.txt
dirA/catC/test-5.txt
dirA/catC/test-7.txt
dirA/catC/test-8.txt
dirA/catC/test-10.txt
dirA/catC/test-11.txt
dirA/catC/test-20.txt
dirA/catC/test-25.txt
dirA/catC/test-50.txt
dirA/catC/test-75.txt
dirA/catC/test-100.txt
dirA/catC/test-500.txt
dirA/catC/test-1000.txt

答え1

Perlが救出に来る!

perl -e '
    print for sort { (($a =~ m{.*/([^0-9]*)})[0] cmp ($b =~ m{.*/([^0-9]*)})[0])
                     ||
                     (($a =~ /-([0-9]+)/)[0] <=> ($b =~ /-([0-9]+)/)[0]) } <>
' -- /tmp/foo.txt
  • <>入力ラインを読む
  • タイプ与えられたコードに基づいてリストをソートします。
  • m{.*/([^0-9]*)}デフォルト名がある場合は、最大1つの数字まで抽出します。
  • cmp文字列比較の実行
  • 同じ場合、ORは||2番目の比較を適用します。
  • /-([0-9]+)/数値抽出
  • <=>数値比較
  • (...)[0]matchは一致リスト(などに対応)を返すため、この設定が$1必要です$2。一致を取得するには、リストコンテキストが必要です。私たちは最初のゲームに興味があります(他のゲームはありません)。

答え2

awk '
    BEGIN {FS = "[-/.]"; OFS = "\t"}
    {n = 0}
    $(NF-1) ~ /^[0-9]+$/ {n = $(NF-1)}
    {print $3, n, $0}
' foo.txt \
| sort -k1,1 -k2,2n \
| cut -f3-

これはシュワルツ変換:

  • awkプログラムは、ファイル名の最初の単語とファイル番号をファイルパスの前に列として追加します。
  • データが名前順にソートされ、次に番号順にソートされる
  • その後、新しい列が削除されます。

出力

dirA/catC/abc-test-8.txt
dirA/catC/abc-test-9.txt
dirA/catC/abc-test-75.txt
dirA/catC/abc-test-999.txt
dirA/catA/addition.txt
dirA/catA/apple.txt
dirA/catB/binary.txt
dirA/catB/carry.txt
dirA/catA/difference
dirA/catB/digit
dirA/catC/test-2.txt
dirA/catC/test-5.txt
dirA/catC/test-7.txt
dirA/catC/test-8.txt
dirA/catC/test-10.txt
dirA/catC/test-11.txt
dirA/catC/test-20.txt
dirA/catC/test-25.txt
dirA/catC/test-50.txt
dirA/catC/test-75.txt
dirA/catC/test-100.txt
dirA/catC/test-500.txt
dirA/catC/test-1000.txt

Perl 1行のプロセスと同じです(Perlステートメントを「ボトムアップ」として読むことを除いて)。

perl -e '
  print join "",
        map  { $_->[2] }
        sort { $a->[0] cmp $b->[0] || $a->[1] <=> $b->[1] }
        map  { [m{.*/(\D+)(\d*)}, $_] }
        <>;
' foo.txt

答え3

sedを使用してください:

cat /tmp/foo.txt | sed "s/[[:alnum:]-]*\/[[:alnum:]-]*\/\([[:alpha:]-]*\)\([[:digit:]]*\).*/\0|\1|\2 /"|sort -t"|" -k2,2 -k3n|sed "s/\([^|]*\).*/\1/"

ヒントは、必須フィールドを行末に一時的に配置することです。

こんにちは:これは良いです:

cat source | sed "s/[^/]*\/[^/]*\/\([^[:digit:]]*\)\([[:digit:]]*\).*/\0|\1|\2 /"|sort -t"|" -k2,2 -k3n|sed "s/\([^|]*\).*/\1/"

元の質問をいくつか変更しました。数字なしで姓で並べ替えます。

dirA/catC/abc-test-8.txt
dirA/catC/abc-test-9.txt
dirA/catC/abc-test-75.txt
dirA/catC/abc-test-999.txt
dirA/catA/addition.txt
dirA/catA/apple.txt
dirA/catB/binary.txt
dirA/catB/carry.txt
dirA/catA/difference
dirA/catB/digit
dirA/catC/test-2.txt
dirA/catC/test-5.txt
dirA/catC/test-7.txt
dirA/catC/test-8.txt
dirA/catC/test-10.txt
dirA/catC/subdir/test-11.txt
dirA/catC/test-11.txt
dirA/cat C/subdir/test-12.txt
dirA/catC/test-20.txt
dirA/catC/test-25.txt
dirA/catC/test-50.txt
dirA/catC/test-75.txt
dirA/catC/test-100.txt
dirA/catC/test-500.txt
dirA/catC/test-1000.txt
cat /tmp/foo.txt | sed "s/\([^/]*\/\)\+\([^[:digit:]]*\)\([[:digit:]]*\)\(.*\)/\0|\2\4|\3 /"|sort -t"|" -k2,2 -k3n|sed "s/\([^|]*\).*/\1/"

出力:

dirA/catC/abc-test-8.txt
dirA/catC/abc-test-9.txt
dirA/catC/abc-test-75.txt
dirA/catC/abc-test-999.txt
dirA/catA/addition.txt
dirA/catA/apple.txt
dirA/catB/binary.txt
dirA/catB/carry.txt
dirA/catA/difference
dirA/catB/digit
dirA/catC/test-2.txt
dirA/catC/test-5.txt
dirA/catC/test-7.txt
dirA/catC/test-8.txt
dirA/catC/test-10.txt
dirA/catC/subdir/test-11.txt
dirA/catC/test-11.txt
dirA/cat C/subdir/test-12.txt
dirA/catC/test-20.txt
dirA/catC/test-25.txt
dirA/catC/test-50.txt
dirA/catC/test-75.txt
dirA/catC/test-100.txt
dirA/catC/test-500.txt
dirA/catC/test-1000.txt

説明: \([^/]*\/\)\+フルパスを切り取ります。 =>\1

\([^[:digit:]]*\)ファイル名に数字が含まれていません。 =>\2

\([[:digit:]]*\)番号=>3 \(.*\)拡張子=>4

\0|\2\4|\3フルライン印刷|ファイル名と拡張子番号の最初の部分|

sort -t"|" -k2,2 -k3n|sed "s/\([^|]*\).*/\1/不要な部分を整理して切り取ります。

最後のsedの代わりにもcut -d "|" -f1動作します

関連情報