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
그러나 or sh
등 의 버전에 따라 확장 zsh
방법에 대해 서로 다른 생각이 있을 수 있다는 생각이 들었습니다 *
.
페이지 man bash
에서는 확장이 *
일치하는 파일 이름의 알파벳순 오름차순 목록인지 여부를 밝히지 않습니다. 내가 사용할 수 있는 모든 시스템에서 시도할 때마다 상승하는 것 같습니다. 그러나 이것이 정의된 동작입니까, 아니면 단지 구현에 특정한 것입니까?
즉, cat /tmp/logs/log*
모든 로그 파일을 알파벳 순서로 연결하는 데 절대적으로 의존할 수 있습니까?
답변1
모든 쉘에서 glob은 기본적으로 정렬됩니다.그들은 이미 도우미 옆에 /etc/glob
있었습니다70년대 초 Unix의 첫 번째 버전에서 글로브를 확장하기 위해 Ken Thompson의 쉘에 의해 호출되었습니다(그리고 글로브에 이름을 부여했습니다).
의 경우 sh
POSIX에서는 를 통해 정렬해야 합니다. 즉 , 일부는 여전히 를 통해 수행하지만 바이트 값만을 기반으로 하는 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
위에서 로케일을 기준으로 정렬하는 쉘의 경우, 여기 로케일이 있는 GNU 시스템에서는 en_GB.UTF-8
정렬 -
시 파일 이름의 가 무시된다는 점을 알 수 있습니다(대부분의 구두점 문자는 그렇습니다). The 는 ó
좀 더 예상되는 방식으로(적어도 영국인에게는) 정렬되고, 대소문자는 무시됩니다(동점을 결정하는 경우를 제외하고).
그러나 log① log②에 대해 일부 불일치가 있음을 알 수 있습니다. 그 이유는 ①과 ②의 정렬 순서가 GNU 로케일에 정의되어 있지 않기 때문입니다(현재는 언젠가 수정될 예정입니다). 동일하게 정렬되므로 임의의 결과를 얻을 수 있습니다.
로케일을 변경하면 정렬 순서에 영향을 미칩니다. -like 정렬 을 얻으려면 로케일을 C로 설정할 수 있습니다 strcmp()
.
$ 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 카테고리, 간단히 말해서 이면 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