Bash 와일드카드 및 매개변수 전달

Bash 와일드카드 및 매개변수 전달

다음과 같은 단순화된 bash 스크립트가 있습니다.

#!/bin/bash

files=("$@")

if [ "X$files" = "X" ]; then
  files=$HOME/print/*.pdf;
fi

for file in "${files[@]}"; do
  ls "$file";
done

인수(파일 이름)를 인수로 전달하면 이 스크립트는 올바른 파일 이름을 인쇄합니다. 반면에 매개변수를 전달하지 않으면 다음이 인쇄됩니다.

/home/user/print/*.pdf: No such file or directory

이 경우 파일 이름이 확장되지 않는 이유와 해결 방법은 무엇입니까? 일반적인 "files=$*"보다 선호된다는 것을 읽었기 때문에 files=("$@")AND 구성을 사용했다는 점에 유의하세요 ."${files[@]}"

답변1

files다음과 같이 지정합니다 .스칼라대신 변수대량으로바꾸다.

존재하다

 files=$HOME/print/*.pdf

당신은 일부를 할당하고 있습니다/home/highsciguy/print/*.pdf$files스칼라(문자열이라고도 함) 변수와 같습니다 .

사용:

files=(~/print/*.pdf)

또는

files=("$HOME"/print/*.pdf)

대신에. 쉘은 와일드카드 패턴을 파일 경로 목록으로 확장하고 각 파일 경로를 다음에 할당합니다.$files 대량으로.

glob의 확장은 할당 중에 수행됩니다.

비표준 sh 기능을 사용할 필요는 없으며 sh여기 대신 시스템에서 작동하도록 작성하여 사용할 수 있습니다.bash

#!/bin/sh -

[ "$#" -gt 0 ] || set -- ~/print/*.pdf

for file do
  ls -d -- "$file"
done

set"$@"할당된 위치 매개변수의 배열 입니다 .

또 다른 접근 방식은 저장하는 것입니다.와일드카드 패턴스칼라 변수에서:

files=$HOME/print/*.pdf

$files 그리고 변수가 확장될 때 쉘이 glob을 확장하도록 하십시오 .

IFS= # disable word splitting
for file in $files; do ...

여기에는 $files따옴표가 없기 때문에(일반적으로 수행해서는 안 됨) 확장은 단어 분리(여기에서는 비활성화함) 및 와일드카드/파일 이름 생성의 영향을 받습니다.

따라서 *.pdf 일치하는 파일 목록이 확장됩니다. 그러나 $HOME와일드카드를 포함하면 확장될 수도 있으므로 배열 변수를 사용하는 것이 더 좋습니다.

답변2

배열이 없는 오래된 쉘에서 and then files=$*같은 것을 본 적이 있을 것입니다 .files=~/print/*.pdfls $files

큰따옴표로 묶이지 않은 변수 대체는 변수 값을 일치하는 파일 이름(있는 경우)으로 대체되는 공백으로 구분된 쉘 와일드카드 패턴 목록으로 해석합니다. 예를 들어, after는 files=~/print/*.pdf매개 변수 등과 유사한 것으로 ls $files확장됩니다 . 이 경우 이 할당은 스크립트에 전달된 인수를 공백으로 연결한 다음 다시 분할합니다.ls/home/highsciguy/print/bar.pdf/home/highsciguy/print/foo.pdffiles=$*ls $files

파일 이름에 공백이나 와일드카드가 포함되어 있으면 이 모든 작업이 실패하므로 이 작업을 수행하면 안 됩니다. 대신 배열을 사용하세요.

files=("$@")
if ((${#files[@]} == 0)); then
  files=("$HOME"/print/*.pdf)
fi

알아채다

  • 모든 배열 할당에는 배열 값을 괄호로 묶어야 합니다 var=(…).
  • 배열이 비어 있는지 테스트하려면 배열의 길이를 확인하세요. 인덱스 0의 요소가 설정되지 않은 배열이거나 빈 문자열인 경우 "$files"비어 있습니다 . null 허용 여부를 테스트하는 더 이상 사용되지 않는 방법 files도 있습니다 . 모든 최신 셸은 이를 올바르게 구현합니다. bash에서는 .[ "X$foo" = "X" ]$foo[ -n "$foo" ][[ -n $foo ]]

배열을 지원하지 않는 쉘에는 실제로 하나의 배열(쉘의 위치 인수 또는 현재 함수)만 있습니다. 여기서는 실제로 배열이 필요하지 않습니다 files. 실제로 위치 매개변수를 사용하는 것이 더 쉬울 것입니다.

#!/bin/sh
if [ "$#" -eq 0 ]; then
  set -- ~/print/*.pdf
fi
for file do …

관련 정보