extglob
Bash에서 쉘 옵션을 활성화하면 negate glob(from man bash
)과 같은 멋진 작업을 수행할 수 있습니다.
If the extglob shell option is enabled using the shopt builtin, sev‐
eral extended pattern matching operators are recognized. In the fol‐
lowing description, a pattern-list is a list of one or more patterns
separated by a |. Composite patterns may be formed using one or more
of the following sub-patterns:
?(pattern-list)
Matches zero or one occurrence of the given patterns
*(pattern-list)
Matches zero or more occurrences of the given patterns
+(pattern-list)
Matches one or more occurrences of the given patterns
@(pattern-list)
Matches one of the given patterns
!(pattern-list)
Matches anything except one of the given patterns
예를 들어:
$ ls
a1file a2file b1file b2file
$ shopt -s extglob
$ ls !(a*)
b1file b2file
이제 디렉토리에서 특정 작업만 수행하려면 다음을 사용할 수 있습니다 */
.
$ ls -F
a1file a2file adir/ b1file b2file bdir/
$ ls -d */
adir/ bdir/
그러나 glob은 */
분명히 부정할 수 없습니다.
$ ls -Fd !(*/)
a1file a2file adir/ b1file b2file bdir/
무엇을 제공합니까? 디렉토리만 올바르게 포함하는데 !(*/)
디렉토리를 제외 하지 않는 이유는 무엇입니까? */
Bash에서 glob을 사용하여 디렉터리를 제외하는 방법이 있습니까?
위 명령은 GNU bash 버전 5.1.8(1) 릴리스를 사용하는 Arch Linux 시스템에서 테스트되었습니다.
답변1
/
구체가 국경을 넘지 않기 때문입니다 . 특별한 경우를 제외하고 **/
(원래 zsh
,이제 다른 껍질에서도 발견됩니다.일반적으로 옵션( shopt -s globstar
bash의 경우)을 설정한 후 glob 연산자는 /
디렉토리 목록에 적용되므로 a가 포함된 어떤 항목과도 일치할 수 없습니다.
쉘은 s 에서 구를 분할합니다 x/y/z
. 각 구성 요소에 대해 구성 요소에 glob 연산자가 포함되어 있으면 셸은 상위 디렉터리를 나열하고 각 항목의 패턴을 다시 일치시킵니다. 그렇지 않은 경우 ²가 있는 파일 /
만 찾습니다 .lstat()
a*b/c
일치하는 항목이 없다는 것을 알게 될 것입니다 a/b/c
. 쉘은 a*b
현재 디렉토리의 항목만 일치합니다. Even 은 별도 의 로 [a/b]*
처리됩니다 .[a
b]*
/
*/
그것은 존재 *
하며 그것과 별개로 존재하는 것은 없습니다 /
. */x
이는 쉘이 먼저 현재 디렉토리 목록과 일치하는 모든 파일을 찾은 다음 각 파일에 대해 이름이 지정된 파일이 존재하는지 확인하려고 시도하는 특별한 경우입니다 *
( 경우 연산자를 사용하여file/x
이 존재하는지 확인한다는 점을 제외하면 동일합니다 ( 디렉토리이거나 디렉토리에 대한 심볼릭 링크인 경우에만 정확함).lstat()
x
*/
file/
file
/
ksh-style @(...)
, ... 확산 연산자( 또는 에서 사용할 수 있는 !(...)
하위 집합 ) 내에서 사용하는 경우 동작은 쉘마다 다르지만 일반적으로 glob 때문에 원하는 작업을 수행하지 않습니다. 의 패턴은 다음과 일치하는 파일에만 일치합니다. 디렉토리 목록의 이름. 의 모든 (숨겨지지 않은) 파일 이름과 일치합니다 . 아마도 여기서 glob이 분할되지 않고 각 디렉토리 항목 이름을 역으로 확인 하고 디렉토리 항목 이름을 포함할 수 없기 때문일 것입니다 . 이것은 실제로 왜 여전히 포함되는지 설명하지 않습니다. s 또는 s를 포함하는 파일 이름 또는 s를 포함하는 파일 이름은 제외되지만 s 또는 s를 포함하는 파일 이름 은 제외되지 않는 이유.bash -O extglob
zsh -o kshglob
bash
!(*/)
/
*/
/
!(*[a/b]*)
a
b
!(*[a")"/b])
a
)
b
유형이 지정되지 않은 파일을 원하는 경우목차심볼릭 링크 확인 후에는 glob 단독으로 수행할 수 있는 작업이 아니며 zsh
실제로 이름 이외의 속성을 기반으로 파일을 선택할 수 있는 glob 한정자를 사용해야 합니다.
print -rC1 -- *(-^/)
여기서 zsh는 glob을 일치시킨 다음 globbing 후 추가 단계로 한정자를 적용합니다. 이는 -
기호 링크 확인 후( stat()
대신 lstat()
) 다음 한정자가 적용되고, ^
다음 한정자가 무효화되고, /
파일 유형이 선택되도록 지정합니다.목차.
4.4+ 에서는 항상 NUL로 구분된 결과를 인쇄하고 이를 사용하여 결과를 얻는 bash
다른 도구에 작업을 아웃소싱할 수 있습니다 . 예를 들면 다음과 같습니다.readarray -td ''
readarray -td '' files < <(zsh -c 'print -rNC1 -- *(N^-.)')
(( ${#files[@]} )) && ls -Fd -- "${files[@]}"
또는 GNU를 사용 find
하고 다음을 수행하십시오 sort
.
readarray -td '' files < <(
LC_ALL=C find . -mindepth 1 -maxdepth 1 \
! -name '.*' ! -xtype d -printf '%P\0' | sort -z)
(( ${#files[@]} )) && ls -Fd -- "${files[@]}"
sort
(이것은 와 동일한 목록을 얻기 위해 목록을 정렬 zsh
하지만 해당 목록을 에 전달하는 특별한 경우에는 자체 정렬과 마찬가지로 중복됩니다. ls
)ls
NUL로 구분된 목록이 있는 경우 배열 단계를 건너뛰고 출력을 에 전달할 수도 있습니다 xargs -r0 ls -Fd --
. 이렇게 하면 빈 목록 사례를 특별히 처리하고 해결하지 않아도 됩니다.인수 목록이 너무 깁니다.한정.
1 그러나 경로를 필터링하고 전체에서 일치시키기 위해 전체 glob 이후 추가 단계로 적용할 수 있는 ~
확장된 glob 연산자 도 참조하세요. 에서는 glob에 대한 파일 이름 생성 알고리즘을 수행 한 다음 패턴을 사용하여 결과 경로 이름을 필터링합니다 .zsh
/
a*/b*/c*~*e*
a*/b*/c*
*e*
² 대소문자를 구분하지 않는 와일드카드를 사용하면 다음과 같이 이를 변경할 수 있습니다.zsh -o nocaseglob