정렬하고 싶어요
- 파일 이름을 기준으로 합니다.
- 파일 이름 접두사가 일치하고 파일이 숫자로 끝나는 경우 파일 이름 끝에 있는 숫자를 기준으로 숫자로 정렬하고 싶습니다.
다음과 같은
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
작동합니다