와일드카드와 공백을 사용하여 파일 이름 나열

와일드카드와 공백을 사용하여 파일 이름 나열

다음 예제와 같이 변수에 지정된 파일을 나열할 수 있어야 합니다.

X="myfile.txt"
$ ls ${X}

불행히도 일부 사람들은 파일 이름에 공백을 사용하므로 다음과 같은 경우가 될 수 있습니다.

X="my file.txt"

다음 방법으로 해결 가능합니다ls "${X}"

그러나 다음과 같은 경우에도 이런 일이 발생할 수 있습니다.

X="my file.*"

와일드카드는 큰따옴표 내에서 확장되지 않기 때문에 문제가 발생합니다.

모든 상황에 적용되는 것이 있나요?

편집하다

X다음과 같은 배열로 선언됩니다 .

X=("my file."*)
ls "$X[@]"

선언할 때 와일드카드 문자를 확장하므로 충분하지 않습니다. 사용할 때 확장해야 합니다 ls.

답변1

세게 때리다

에서는 bash변수를 인용 해제하는 것을 분할+글로브 연산자라고 부르기도 합니다.

분할 부분은 $IFS특수 매개변수를 사용하여 조정할 수 있으며, 전역 부분은 noglob다음 옵션을 사용하여 조정할 수 있습니다.

와일드카드의 경우에만 $IFS빈 문자열로 설정합니다.

file_pattern='foo bar *.txt'
IFS= # disable splitting
set +o noglob # make sure glob is enabled
ls -ld -- $file_pattern # split+glog with split disabled.

패턴이 어떤 파일과도 일치하지 않으면 ls리터럴 인수를 받고 foo bar *.txt파일이 존재하지 않는다고 불평합니다.

분할에 대해서만( $PATH여기서는 콜론으로 구분된 변수 분할이 예제로 사용됨) noglob옵션을 설정합니다.

IFS=: # split on :
set -o noglob
ls -ld -- $PATH # split+glob with glob disabled

비어 있거나 설정되지 않은 경우 $var, 비어 있더라도 확장 시 인수가 생성되지 않고 빈 인수가 생성됩니다 $IFS.

$PATH비어 있음 $PATH( unset 아님 $PATH)은 명령이 현재 작업 디렉터리에서 검색되고 ls인수가 전달되지 않을 때 현재 작업 디렉터리도 나열된다는 의미 이기 때문에 여기서는 허용됩니다 .

$PATH현재 작업 디렉터리를 의미하는 (예: ) 에 빈 요소가 있는 경우 이에 대해 불평하는 /bin::/usr/bin해당 빈 인수가 전달됩니다 . ls한 가지 예외는 빈 요소가 마지막 요소인 경우( 에서와 같이 /bin:/usr/bin:) 마지막 요소가 삭제된다는 것입니다.

유사한 변수를 분할하는 더 올바른 방법은 다음을 $PATH사용하는 것입니다.

IFS=:
set -o noglob
printf '<%s>\n' $PATH''

이 추가 부분은 ''뒤에 오는 빈 요소가 제거되는 것을 방지하고 빈 요소가 $PATH전혀 요소가 아닌 빈 요소로 분할되도록 보장합니다.

다루기 힘든

zsh에서는 인수 확장 중에 분할 및 와일드카드가 암시적으로 수행되지 않습니다. $=var- $IFS분할, ${(s[separator])var}구분 기호 기반 분할, $~var와일드카드(또는 -분할과 와일드카드 $=~var결합 ) $IFS를 사용하여 명시적으로 요청 해야 합니다.

그래서:

file_pattern='foo bar *.txt'
ls -ld -- $~file_pattern

(패턴이 어떤 파일과도 일치하지 않으면 명령이 ls중단됩니다²).

IFS=:
ls -ld -- $=PATH # preserves all empty elements even trailing ones
ls -ld -- ${(s[:])PATH}    # split, discarding empty elements
ls -ld -- "${(@s[:])PATH}" # split, preserving empty elements

¹ 이 옵션을 활성화하지 않는 한(관리형이 아닌 다른 옵션 세트에서 failglob) bash는 중단됩니다(하위 쉘을 종료하거나 하위 쉘에서 실행되지 않는 경우 읽은 모든 코드를 건너뜁니다). 또는 이 옵션을 활성화하면 다음으로 확장됩니다. 이 경우에는 아무것도 없으므로 현재 작업 디렉터리가 나열됩니다.shoptsetnullglob shoptls

² zsh에서 실패한 glob은 구문 오류처럼 처리되며 해당 쉘 프로세스는 오류 및 실패한 종료 상태로 종료됩니다(대화형 쉘에서는 기본 쉘을 종료하지 않고 프롬프트로 돌아갑니다). 여기서는 외부 명령과 마찬가지로 ls이를 실행하기 위해 생성된 하위 프로세스만 종료됩니다. 전역 확장이 여기서 발생하기 때문입니다. ls예를 들어 쉘 함수로 다시 정의하면 상황이 달라집니다.

답변2

와일드카드를 사용하려는 경우 변수를 사용하는 것은 여러 파일과 일치할 수 있으므로 좋은 생각이 아닙니다.

해결책: 배열을 사용하세요!

X=("my file."*)
ls "${X[@]}"

# or

for f in "${X[@]}"; do
   some_command "$f"
done

값을 할당할 때는 *따옴표 밖에 있어야 합니다.

확인하다여기변수 확장시에만 전역 확장을 위한 솔루션입니다.

관련 정보