비슷한 이름을 가진 파일들로 가득 찬 디렉토리가 있습니다. logXX
여기서 XX는 0으로 채워진 대문자 16진수 숫자입니다. 예를 들면 다음과 같습니다.
log00
log01
log02
...
log0A
log0B
log0C
...
log4E
log4F
log50
...
일반적으로 총 파일 수는 20~30개 미만입니다. 내 특정 시스템(신뢰할 수 있는 NTP 또는 GPS 시간 소스가 없는 내장 시스템)에서 날짜와 시간을 신뢰할 수 없습니다. 그러나 파일 이름은 위에 표시된 대로 안정적으로 증가합니다.
특정 유형의 최신 단일 로그 항목에 대해 모든 파일을 반복 하고 싶습니다 . 예를 들어 이러한 파일을 함께 배치하고 grep
싶습니다 .cat
cat /tmp/logs/log* | grep 'WARNING 07 -' | tail -n1
bash
그러나 다른 버전 이나 sh
다른 버전은 확장 zsh
방법에 대해 *
다른 아이디어를 가질 수 있다는 생각이 듭니다 .
이 man bash
페이지에서는 확장명이 *
일치하는 파일 이름의 명시적인 오름차순 알파벳 목록인지 여부를 밝히지 않습니다. 사용 가능한 모든 시스템에서 시도할 때마다 증가하는 것 같습니다. 하지만 정의된 동작인가요, 아니면 구현에 따라 달라지나요?
즉, cat /tmp/logs/log*
모든 로그 파일을 알파벳 순서로 연결하는 데 절대적으로 의존할 수 있습니까?
답변1
모든 쉘에서 glob은 기본적으로 정렬됩니다.그들은 이미 /etc/glob
어시스턴트 와 함께 있습니다1970년대 초 Unix의 첫 번째 버전에서 glob(따라서 glob이라는 이름)을 확장하기 위해 Ken Thompson의 쉘에 의해 호출되었습니다.
POSIX 에서는 for 와 같이 사용자 로케일의 정렬 순서를 사용하여 sh
정렬해야 하지만 일부는 여전히 바이트 값만을 기준으로 정렬 됩니다.strcoll()
ls
strcmp()
$ dash -c 'echo *'
Log01B log-0D log00 log01 log02 log0A log0B log0C log4E log4F log50 log① log② lóg01
$ bash -c 'echo *'
log① log② log00 log01 lóg01 Log01B log02 log0A log0B log0C log-0D log4E log4F log50
$ zsh -c 'echo *'
log① log② log00 log01 lóg01 Log01B log02 log0A log0B log0C log-0D log4E log4F log50
$ ls
log② log① log00 log01 lóg01 Log01B log02 log0A log0B log0C log-0D log4E log4F log50
$ ls | sort
log②
log①
log00
log01
lóg01
Log01B
log02
log0A
log0B
log0C
log-0D
log4E
log4F
log50
로케일을 기준으로 정렬되는 쉘의 경우 en_GB.UTF-8
로케일이 있는 GNU 시스템 에서는 -
. 좀 더 기대되는 방식으로 정렬하고 ó
(적어도 영국인의 경우) 대소문자를 무시합니다(관계 결정이 관련되지 않는 한).
그러나 로그 ①과 로그 ② 사이에 약간의 불일치가 있음을 알 수 있습니다. 이는 ①과 ②의 정렬 순서가 GNU 로케일에 정의되어 있지 않기 때문입니다(아직, 언젠가는 수정될 예정입니다). 순서가 동일하므로 무작위 결과가 나옵니다.
로케일을 변경하면 정렬 순서에 영향을 미칩니다. strcmp()
유사한 정렬을 얻으려면 로케일을 C로 설정할 수 있습니다 .
$ bash -c 'echo *'
log① log② log00 log01 lóg01 Log01B log02 log0.2 log0A log0B log0C log-0D log4E log4F log50
$ bash -c 'LC_ALL=C; echo *'
Log01B log-0D log0.2 log00 log01 log02 log0A log0B log0C log4E log4F log50 log① log② lóg01
일부 로케일은 전체 ASCII 전체 문자열을 사용하더라도 약간의 혼동을 일으킬 수 있습니다. 체코 ch
어와 마찬가지로(적어도 GNU 시스템에서는)요소 구성정렬 후 h
:
$ LC_ALL=cs_CZ.UTF-8 bash -c 'echo *'
log0Ah log0Bh log0Dh log0Ch
또는 @ninjalj가 지적했듯이 헝가리 로케일의 낯선 사람도 있습니다.
$ LC_ALL=hu_HU.UTF-8 bash -c 'echo *'
logX LOGx LOGX logZ LOGz LOGZ logY LOGY LOGy
에서 zsh
정렬을 선택할 수 있습니다글로벌 예선. 예를 들어:
echo *(om) # to sort by modification time
echo *(oL) # to sort by size
echo *(On) # for a *reverse* sort by name
echo *(o+myfunction) # sort using a user-defined function
echo *(N) # to NOT sort
echo *(n) # sort by name, but numerically, and so on.
echo *(n)
다음 옵션을 사용하여 숫자 정렬을 전역적으로 활성화할 수도 있습니다 numericglobsort
.
$ zsh -c 'echo *'
log① log② log00 log01 lóg01 Log01B log02 log0.2 log0A log0B log0C log-0D log4E log4F log50
$ zsh -o numericglobsort -c 'echo *'
log① log② log00 lóg01 Log01B log0.2 log0A log0B log0C log01 log02 log-0D log4E log4F log50
당신(나처럼)이 특정 상황에서 주문에 대해 혼란스럽다면(여기서 내 영국 로케일을 사용하여) 다음을 참조하십시오.여기더 알아보기.
답변2
Bash 매뉴얼 페이지에서는 다음을 지정합니다.
경로명 확장
단어 분할 후
-f
bash는 이 옵션이 설정되지 않은 한 문자를 스캔*
하고 각 단어를?
스캔 합니다[
. 이러한 문자 중 하나가 발생하면 해당 단어는 패턴으로 처리되고 [...] 패턴과 일치하는 파일 이름의 알파벳순 목록으로 대체됩니다.
답변3
특정 셸에서 매우 특정한 셸 옵션을 실행하지 않는 한 출력은 동일하다는 것이 보장됩니다.
순서는 다음과 같이 지정됩니다.POSIX 표준:
패턴이 기존 파일 이름 또는 경로 이름과 일치하는 경우 패턴은 해당 파일 이름 및 경로 이름으로 대체되어야 합니다.현재 로케일에서 유효한 조합 순서에 따라 정렬. 이 조합 순서에 모든 문자의 전체 조합이 없는 경우(XBD LC_COLLATE 참조) 동등하게 조합된 모든 파일 이름 또는 경로 이름은 POSIX 로케일의 조합 순서를 사용하여 바이트별로 추가로 비교되어야 합니다.
당신은 또한 볼 수 있습니다POSIX 로케일의 LC_COLLATE 카테고리, 간단히 말해서 if LC_COLLATE=C
는 ASCII 순서로 정렬됩니다.
설명서 bash
에 언급된
LC_COLLATE
이 변수는 경로 이름 확장 결과를 정렬할 때 사용되는 데이터 정렬을 결정하고 범위 표현식, 동등 클래스, 경로 이름 확장 및 패턴 일치의 정렬 순서의 동작을 결정합니다.
ksh93
그리고 zsh
비슷한 표현이 있는데, 이는 그들이 이 점에 있어서 POSIX 표준을 따르고 있다고 믿게 만듭니다.
pdksh
및 등의 다른 셸은 dash
파일 이름 글로빙으로 인한 파일 이름 순서를 고려하지 않습니다. 나는 이것이 적어도 POSIX 로케일을 사용할 때 여전히 동일한 표준을 따른다는 것을 의미한다고 믿고 싶습니다. 내 경험상 아직까지 ASCII 파일 이름의 "이상한" 순서를 지정하는 쉘을 본 적이 없습니다.
답변4
주요 목표가 입력 파일을 연령별로 정렬하는 것이라면 가장 오래된 것부터 다음과 같이 작성할 수 있습니다.
(cd /tmp/logs; cat `ls -rt log*`) | grep whatever
로그 회전 및 압축도 관련된 경우:
(cd /tmp/logs; zcat -f `ls -rt log*`) | grep whatever