다중 열 알파벳 및 숫자 정렬

다중 열 알파벳 및 숫자 정렬

정렬하고 싶어요

  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은 ||두 번째 비교를 적용합니다.
  • /-([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 한 줄짜리 프로세스와 동일합니다(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작동합니다

관련 정보