아래와 같이 "teleport.sh"라는 쉘 스크립트가 있습니다.
if [ $1="1" ];
then
shift
mv "$@" ~/lab/Sun
elif [ $1="2" ];
then
shift
mv "$@" ~/lab/Moon
elif [ $1="3" ];
then
shift
mv "$@" ~/lab/Earth
fi
내가 실행할 때 :
sh teleport.sh 2 testfile
이것은 디렉토리 testfile
로 이동되는데 ~/lab/Sun
, 스크립트에 1 또는 "1"을 전달하지 않기 때문에 혼란스럽습니다.
어떻게 되어가나요?
답변1
공백을 사용하면 문제가 해결될 수 있습니다.
if [ "$1" = 1 ];
then
shift
mv "$@" ~/lab/Sun
elif [ "$1" = 2 ];
then
shift
mv "$@" ~/lab/Moon
elif [ "$1" = 3 ];
then
shift
mv "$@" ~/lab/Earth
fi
이것이 더 깔끔하지만:
#!/bin/bash
action=$1
shift
files=("$@")
case $action in
1) mv -- "${files[@]}" ~/lab/Sun ;;
2) mv -- "${files[@]}" ~/lab/Moon ;;
3) mv -- "${files[@]}" ~/lab/Earth ;;
esac
답변2
[
첫 번째로 확실한 점은 test
, 또는 인수 사이에 공백을 제공 해야 한다는 것입니다 [[
.
if [ "$1" = 1 ];
Bash에서는 [[ ]]
토큰화, 경로명 확장 등 조건식에 불필요한 작업을 수행하지 않기 때문에 using을 사용하는 것이 좋습니다. 큰따옴표로 묶을 필요도 없습니다. ==
더 읽기 쉬운 연산자를 사용할 수도 있습니다.
if [[ $1 == 1 ]];
*
추가된 설명: 두 번째 피연산자에도 변수가 포함되어 있으면 따옴표로 묶어야 합니다. 인식된 문자(예: 등)가 포함되어 있으면 ?
패턴 일치의 영향을 받을 수 있기 때문입니다. 사용되는 경우 다른 형식(예: 등)을 사용 []
하면 확장된 와일드카드 또는 패턴 일치가 가능합니다. 패턴으로도 인식됩니다. 바라보다shopt -s extglob
@()
!()
패턴 매칭.
<
같은 연산자 의 경우 >
두 번째 인수를 인용하지 않으면 다른 결과가 나오는 버그가 발생했기 때문에 여전히 필요할 수 있습니다.
첫 번째 피연산자는 아무 것도 적용되지 않습니다.
또한 다음과 같은 간단한 변형을 고려하십시오.
case "$1" in
1)
mv -- "${@:2}" ~/lab/Sun
;;
2)
mv -- "${@:2}" ~/lab/Moon
;;
3)
mv -- "${@:2}" ~/lab/Earth
;;
esac
또는 요약하면 다음과 같습니다.
case "$1" in
1) mv -- "${@:2}" ~/lab/Sun ;;
2) mv -- "${@:2}" ~/lab/Moon ;;
3) mv -- "${@:2}" ~/lab/Earth ;;
esac
"${@:2}"
부분 문자열 확장 또는 배열 멤버 확장의 형태입니다. 여기서 2
는 오프셋입니다. 그러면 두 번째 값부터 확장이 시작됩니다. 이것으로 우리는 그것을 사용할 필요가 없을 것입니다 shift
.
대시( ) 로 시작하는 파일 이름이 잘못된 옵션으로 인식되는 것을 --
방지하는 기능이 추가되었습니다 .mv
-
답변3
왜 이런 일이 발생하는지에 대한 질문에 답하기 위해 [
일명 이 동작 test
은POSIX에 문서화됨:
다음 목록에서 $1, $2, $3 및 $4는 테스트할 매개변수를 나타냅니다.
[...]
매개변수 1개:
$1이 null이 아니면 true(0)를 반환하고, 그렇지 않으면 false를 반환합니다.
2=1
null이 아닌 1개의 매개변수를 전달했으므로 test
성공적으로 종료되었습니다.
다른 게시물과 마찬가지로 (그리고주택 검사)는 동등성을 비교하려면 3개의 인수 및 을 전달 해야 함을 나타냅니다 2
.=
1
답변4
하나만 추천하고 싶어요가지고 다닐 수 있는그러나 그것은 또한 더 깨끗한 옵션이기도 합니다. 쿵쿵이다아니요Universal(유니버설이 필요하지 않은데 왜 쉘 스크립트를 작성합니까?)
#! /bin/sh
action="$1"
shift
case "$action" in
1) dest=Sun ;;
2) dest=Moon ;;
3) dest=Earth ;;
*) echo "Unrecognized action code '$action' (must be 1, 2, or 3)" >&2; exit 1 ;;
esac
mv -- "$@" ~/lab/"$dest"
$action
(현자들을 위한 참고 사항: 예, 인라인 인용문이 case "$action" in
불필요하다는 것을 알고 있지만 미래의 독자들이 이것을 기억할 필요가 없도록 인용문을 거기에 두는 것이 더 낫다고 생각합니다.)