Bash star * 와일드 카드는 항상 (오름차순) 정렬 목록을 생성합니까?


53

logXXXX는 다음 과 같은 이름을 가진 파일로 채워진 디렉토리가 있습니다 .

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
@ADDB 기본 정렬 순서 sort는 파일 이름 글 로빙 패턴을 확장 할 때의 셸과 동일합니다.
Kusalananda

9
끔찍한 파일 명명 연습입니다. log (0) =-infty로 실행을 시작하는 이유는 무엇입니까?
EP

14
@EP 파일 시스템은 초현실적 인 inode 번호를 가진 복잡한 7 차원 하이퍼-토 로이드입니다. 그것은 busybox의 모호한 지점으로 할아버지가되었으며 지금 우리는 그것을 재치했습니다 :)
Wossname

1
당신은 피할 수 catgrep -h pattern /tmp/logs/log*일치하는에 파일 이름을 붙이는 억제 할 수 있습니다. (최소한 GNU grep에서는 POSIX 또는 busybox를 확인하지 않았습니다.)
Peter Cordes

1
@Kusalananda 당신은 쓸모없는 사용에 대해 들었습니다 cat, 이것은 쓸모없는 사용입니다sort
cat

답변:


52

모든 쉘에서 글롭은 기본적으로 정렬됩니다. 그들은 이미/etc/glob 70 년대 초 유닉스의 첫 번째 버전에서 글로브를 확장하기 위해 Ken Thompson의 쉘에 의해 호출 된 도우미에 의해있었습니다 (그리고 글로브에 이름을 지어주었습니다).

의 경우 shPOSIX는을 기준으로 정렬해야합니다 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경우) -에서 파일 이름의 정렬은 무시됩니다 (대부분의 문장 부호 문자). 이 ó방식은보다 예상 된 방식으로 정렬되며 (적어도 영국인에게는 해당) 대소 문자는 무시됩니다 (관계 결정시 제외).

그러나 log① log②에는 약간의 불일치가 있습니다. 이것은 ①과 ②의 정렬 순서가 GNU 로켈에서 정의되어 있지 않기 때문입니다 (현재는 희망적으로 언젠가는 고쳐질 것입니다). 그들은 동일하게 정렬되므로 임의의 결과를 얻습니다.

로캘을 변경하면 정렬 순서에 영향을줍니다. 로케일을 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 문자열에 대해서도 일부 로케일이 혼동을 일으킬 수 있습니다. 체코 어와 마찬가지로 (적어도 GNU 시스템에서는) 다음 ch과 같은 정렬 요소 가 있습니다 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, glob 한정자를 사용 하여 정렬을 선택할 수 있습니다 . 예를 들어 :

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

당신이 (나와 같이) 특정 인스턴스 (여기서 영국 로케일을 사용하는)의 순서로 혼란 스러우면 여기 를 참조하십시오.


1
'ch'경우는 더 이상 할 수 있습니다. 일부 로케일은 'ch', 'Ch'및 'CH'가 각각 1 개의 조합 요소이고 'cH'는 2 개의 조합 요소라고 결정할 수 있습니다. 참조 : unicode.org/cldr/trac/ticket/889 현재 CLDR이 완전히 일관성이없는 것 같습니다 : 현재 헝가리어 ( unicode.org/cldr/trac/browser/trunk/common/collation/hu.xml )에는 다음과 같은 규칙이 있습니다. &C<cs<<<Cs<<<CS, &C<cs<<<cS<<<Cs<<<CS제안 된 실험 초안으로 표시됩니다. CLDR로 가져온 일부 이전 데이터에서 볼 때 이전 AIX 및 MS는 "소문자가 대문자 인 경우 2 개의 서로 다른 조합 요소"보기를 선호하는 것 같습니다.
ninjalj 2016 년

어쨌든 작동하지 않는 시스템을 보았습니다. :(
Joshua

38

bash의 맨 페이지는 다음을 지정합니다.

경로명 확장

하지 않는 단어 분할 후 -f옵션이 설정되어, 배쉬는 문자에 대한 각 단어를 검색 *, ?[. 이러한 문자 중 하나가 나타나면 단어는 패턴으로 간주되고 패턴 […]과 일치하는 알파벳순으로 정렬 된 파일 이름 목록으로 대체됩니다.


1
퍼티 또는 man의 텍스트 렌더링 에서 흥미로운 버그를 발견했습니다. 검색중인 텍스트가 "단어 줄 바꿈"을 받으면 / search 명령에서 찾을 수 없습니다. 그냥 내 터미널을 최대화하고 거기에 있습니다 :)
Wossname

2
당신은 덮었다 bash. Tho OP는 "zsh 등"에도 관심이있었습니다.
Kusalananda

29

일부 쉘에서 매우 특정한 쉘 옵션을 트리거하지 않으면 출력이 동일하게 보장됩니다.

순서는 POSIX 표준에 지정되어 있습니다 .

패턴이 기존 파일 이름 또는 경로 이름과 일치하면 패턴이 해당 로케일 및 경로 이름으로 바뀌고 현재 로케일에서 유효한 조합 순서에 따라 정렬됩니다 . 이 조합 순서가 모든 문자의 총 순서를 갖지 않으면 (XBD LC_COLLATE 참조) 동일하게 조합 된 파일 이름 또는 경로 이름은 POSIX 로케일의 조합 순서를 사용하여 바이트 단위로 더 비교되어야합니다.

POSIX 로케일의 LC_COLLATE 카테고리를 참조하십시오. 간단히 말하면 LC_COLLATE=CASCII 순서로 정렬됩니다.


bash매뉴얼은 언급

LC_COLLATE

이 변수는 경로 이름 확장 결과를 정렬 할 때 사용되는 데이터 정렬 순서를 결정하고 경로 이름 확장 및 패턴 일치 내의 범위 표현식, 동등성 클래스 및 배열 시퀀스의 동작을 결정합니다.

ksh93그리고 zsh그들은이 점에서 POSIX 표준에 따라 믿고 날 리드 유사한 표현을 가지고 있습니다.

다른 쉘은, 같은 pdkshdash파일 이름 대체 (globbing)에서 발생하는 파일 이름의 정렬에 대해 아무 말도하지 않습니다. 최소한 POSIX 로캘을 사용할 때 동일한 표준을 준수한다는 의미입니다. 내 경험상 ASCII 파일 이름을 "이상하게"정렬하는 쉘을 발견하지 못했습니다.


2
정렬에 영향을 줄 수 있는 numericglobsort옵션을 참조하십시오 zsh. echo *(n)옵션을 전 세계적으로 켜는 것 보다는 지구별로 사용하도록 설정하고 싶지만 .
Stéphane Chazelas

이쑤시개. 기본 모드에서 Bash는 Posix와 호환되지 않습니다.
fpmurphy

더 말해봐.
Kusalananda

@Kusalananda. Bash는 POSIX 불만으로 인증 된 적이 없습니다. Bash에서 "POSIX-compliance"를 얻으려면 --posix명령 행 옵션으로 Bash를 호출 하거나set -o posix
fpmurphy

@ fpmurphy1 예, 그러나 파일 이름 글 로빙 문자의 확장 정렬은 Bash posix모드 의 영향을받지 않습니다 . gnu.org/software/bash/manual/html_node/Bash-POSIX-Mode.html 참조 이것은 정렬이 POSIX 호환이라고 믿게합니다.
Kusalananda

1

주요 목표가 입력 파일을 나이별로 정렬하는 것입니다 (가장 오래된 것부터).

(cd /tmp/logs; cat `ls -rt log*`) | grep whatever

그리고 회전 및 압축 로그도 관련이있는 경우 :

(cd /tmp/logs; zcat -f `ls -rt log*`) | grep whatever

4
파일의 타임 스탬프를 신뢰할 수 없다고 언급했습니다.
Kusalananda

3
@ Kusalananda, 맞아요, 우리 시스템 시간은 일반적으로 난수 생성기로 간주됩니다 :)
Wossname
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.