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.png
graph1.png
$1
A*
algorithm.png
A*
A* algorithm.png
algorithm.png
mv
-n
A* algorithm.png
algorithm.png
targetdir
-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 터미널은 별표를 명령에 직접 전달하지 않고 일치하는 첫 번째 인수를 선택하여 명령에 전달합니다.
별표를 직접 통과하려면 별표를 백슬래시로 이스케이프해야 합니다.