$1이 1이 아닌 경우에도 'if [ $1="1" ]' 분기가 항상 선택되는 이유는 무엇입니까?

$1이 1이 아닌 경우에도 'if [ $1="1" ]' 분기가 항상 선택되는 이유는 무엇입니까?

아래와 같이 "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

왜 이런 일이 발생하는지에 대한 질문에 답하기 위해 [일명 이 동작 testPOSIX에 문서화됨:

다음 목록에서 $1, $2, $3 및 $4는 테스트할 매개변수를 나타냅니다.

[...]

매개변수 1개:

$1이 null이 아니면 true(0)를 반환하고, 그렇지 않으면 false를 반환합니다.

2=1null이 아닌 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불필요하다는 것을 알고 있지만 미래의 독자들이 이것을 기억할 필요가 없도록 인용문을 거기에 두는 것이 더 낫다고 생각합니다.)

관련 정보