"*" 와일드카드 문자를 사용할 때 파일 이동/복사 기능이 한 번에 하나의 파일만 이동하는 이유는 무엇입니까?

"*" 와일드카드 문자를 사용할 때 파일 이동/복사 기능이 한 번에 하나의 파일만 이동하는 이유는 무엇입니까?
function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}
mv1 *.png

.png모든 파일이 아니라 발견된 첫 번째 파일 만 이동합니다 .

와일드카드와 일치하는 모든 파일에 이 명령을 적용하려면 어떻게 해야 합니까?

답변1

mv1 *.png와일드카드 패턴은 먼저 *.png파일 이름 목록과 일치하도록 확장된 다음 파일 이름 목록이 함수에 전달됩니다.

그런 다음 함수 내부에서는 $1첫 번째 인수를 함수에 전달하고, 공백이 포함된 부분을 분할하고, 파일 이름 목록과 일치하여 와일드카드가 포함된 공백으로 구분된 부분을 하나 이상의 파일 이름과 일치하는 것으로 바꿉니다. 복잡하게 들리나요? 그렇습니다. 이 동작은 가끔 유용할 뿐이며 종종 문제를 일으킵니다. 이 분할 및 일치 동작은 $1큰따옴표 외부에서만 발생하므로 수정은 간단합니다. 큰따옴표를 사용하세요.변수 대체에는 항상 큰따옴표를 사용하세요.그렇게 하지 않을 타당한 이유가 없다면 말이죠.

예를 들어, 현재 디렉터리에 두 개의 파일이 포함되어 A* algorithm.png있고 함수의 graph1.png첫 번째 인수로 mv1 *.png전달되고 두 번째 인수로 전달되는 경우입니다. 그런 다음 합계 로 나눕니다 . 패턴이 일치 하지만 와일드카드 문자를 포함하지 않습니다. 따라서 함수는 , 및 매개변수 를 사용하여 실행 됩니다 . 해당 기능을 수정하면A* algorithm.pnggraph1.png$1A*algorithm.pngA*A* algorithm.pngalgorithm.pngmv-nA* algorithm.pngalgorithm.pngtargetdir-v

function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}

그러면 첫 번째 파일이 올바르게 이동됩니다.

다루다모두매개변수는 첫 번째 매개변수 대신 모든 매개변수를 처리하도록 쉘에 지시합니다. "$@"함수에 전달된 인수의 전체 목록을 나타내는 데 사용할 수 있습니다 .

function mv1 { mv -n "$@" "targetdir" -v |wc -l ;}

이는 거의 정확하지만 인수가 옵션으로 처리되므로 -파일 이름이 문자로 시작하면 여전히 실패합니다 . mv전달 --하면 mv"이후에는 더 이상 옵션이 없습니다"라고 알립니다. 이는 대부분의 명령에서 지원되는 매우 일반적인 규칙입니다.

function mv1 { mv -n -v -- "$@" "targetdir" |wc -l ;}

남은 문제는 mv실패할 경우 파이프 왼쪽에 있는 명령의 종료 상태가 무시되기 때문에 함수가 성공 상태를 반환한다는 것입니다. Bash(또는 ksh)에서는 set -o pipefail. 이 옵션을 설정하면 동일한 셸에서 실행되는 다른 코드가 실패할 수 있으므로 함수에서 로컬로 설정해야 하며 이는 bash 4.4부터 가능합니다.

function mv1 {
  local -
  set -o pipefail
  mv -n -v -- "$@" "targetdir" | wc -l
}

이전 버전에서는 설정이 pipefail취약하므로 PIPESTATUS명시적으로 확인하는 것이 가장 좋습니다.

function mv1 {
  mv -n -v -- "$@" "targetdir" | wc -l
  ((!${PIPESTATUS[0] && !${PIPESTATUS[1]}}))
}

답변2

$1은 함수의 첫 번째 매개변수입니다. 여기에 일치하는 첫 번째 파일이 있습니다 *.png. 나는 이것이 "$@"당신이 대신 사용하고 싶은 것 같아요 $1.

답변3

를 사용해야 합니다 mv1 \*.png.

함수와 상호 작용할 때 Linux 터미널은 별표를 명령에 직접 전달하지 않고 일치하는 첫 번째 인수를 선택하여 명령에 전달합니다.

별표를 직접 통과하려면 별표를 백슬래시로 이스케이프해야 합니다.

관련 정보