인수가 있거나없는 스크립트를 작성하는 방법은 무엇입니까?


13

다음과 같은 bash 스크립트가 있습니다.

#!/bin/bash

if [ $1 = "--test" ] || [ $1 = "-t" ]; then
    echo "Testing..."
    testing="y"

else
    testing="n"
    echo "Not testing."

fi

그래서 내가하고 싶은 것은 ./script --test또는로 실행하는 것 ./script -t뿐만 아니라 인수없이 (단지 ./script) 실행하는 것입니다 . 그러나 현재 코드로 그렇게하면 출력은 다음과 같습니다.

./script: line 3: [: =: unary operator expected
./script: line 3: [: =: unary operator expected
Not testing.

그래서 전혀 인수없이 실행 else하면 오류를 발생시키지 않고 어떻게 할 수 있습니까? 내가 도대체 ​​뭘 잘못하고있는 겁니까?


1
수표 주위에 이중 괄호가 필요합니다. [[]]
Terrance


당신이하지 않는 @Terrance 필요 당신이 떠들썩한 파티를 대상으로하는 경우 당신이 그들을 사용해야하지만, 그들.
Ruslan

답변:


1

쉘 스크립팅에서 긴 옵션을 사용하는 "적절한 방법"은 getopt GNU 유틸리티를 사용하는 것 입니다. bash 내장 된 getopts 도 있지만 짧은 옵션 만 허용 -t합니다. getopt사용법에 대한 몇 가지 예는 여기 에서 찾을 수 있습니다 .

다음은 귀하의 질문에 어떻게 접근하는지 보여주는 스크립트입니다. 대부분의 단계에 대한 설명은 스크립트 자체에 주석으로 추가됩니다.

#!/bin/bash

# GNU getopt allows long options. Letters in -o correspond to
# comma-separated list given in --long.

opts=$(getopt -o t --long test -- "$*")
test $? -ne 0 && exit 2 # error happened

set -- $opts # some would prefer using eval set -- "$opts"
# if theres -- as first argument, the script is called without
# option flags
if [ "$1" = "--"  ]; then
    echo "Not testing"
    testing="n"
    # Here we exit, and avoid ever getting to argument parsing loop
    # A more practical case would be to call a function here
    # that performs for no options case
    exit 1
fi

# Although this question asks only for one 
# option flag, the proper use of getopt is with while loop
# That's why it's done so - to show proper form.
while true; do
    case "$1" in
        # spaces are important in the case definition
        -t | --test ) testing="y"; echo "Testing" ;;
    esac
    # Loop will terminate if there's no more  
    # positional parameters to shift
    shift  || break
done

echo "Out of loop"

몇 가지 단순화와 주석 제거를 통해 다음과 같이 요약 할 수 있습니다.

#!/bin/bash
opts=$(getopt -o t --long test -- "$*")
test $? -ne 0 && exit 2 # error happened
set -- $opts    
case "$1" in
    -t | --test ) testing="y"; echo "Testing";;
    --) testing="n"; echo "Not testing";;
esac

16

몇 가지 방법들; 가장 명백한 두 가지는 :

  • $1큰 따옴표를 넣으 십시오.if [ "$1" = "--test" ]
  • $ #를 사용하여 인수 수를 확인하십시오.

더 나은 방법은 getopts를 사용하는 것입니다.


2
getopts 사용시 +1 그것이 가장 좋은 방법입니다.
Seth

3
또 다른 일반적인 관용구는 [ "x$1" = "x--test" ]명령에 유효한 연산자 인 명령 줄 인수를 다시 방어하는 것 [입니다. (이것이 [[ ]]선호되는 또 다른 이유 입니다. 기본 제공 명령이 아니라 쉘 구문의 일부입니다.)
Peter Cordes

7

if 조건 안에서 변수를 인용해야합니다. 바꾸다:

if [ $1 = "--test" ] || [ $1 = "-t" ]; then

와:

if [ "$1" = '--test' ] || [ "$1" = '-t' ]; then  

그런 다음 작동합니다.

➜ ~ ./test.sh
테스트하지 않습니다.

항상 변수를 큰 따옴표로 묶으십시오!


작은 따옴표가 필수적입니까, 아니면 큰 따옴표를 대신 사용할 수 있습니까?

정확한 대답은 사용중인 쉘에 따라 다르지만 귀하의 질문에서 Bourne-shell 자손을 사용한다고 가정합니다. 작은 따옴표와 큰 따옴표의 주요 차이점은 변수 확장은 큰 따옴표 안에 있지만 작은 따옴표 안에는 발생하지 않는다는 것입니다. $ FOO = bar $ echo "$ FOO"bar $ echo '$ FOO'$ FOO (hmm .... can ' 주석의 t 형식 코드 ...)
JayEye

@ParanoidPanda 작은 따옴표를 사용할 필요는 없지만 문자열 리터럴에 사용하는 것이 좋습니다. 이렇게하면 문자열 데이터에 bash가 확장하려는 기호가있는 경우 나중에 놀라지 않을 것입니다.
Seth

@ParanoidPanda @JayEye가 말한 것 : 작은 따옴표를 사용하면 가변 확장 foo=bar echo '$foo'인쇄 $foo가 출력에 출력되지 않고 대신 foo=bar echo "$foo"인쇄 bar됩니다.
EKons

4

bash를 사용하고 있습니다. 강타는 훌륭한 대안이있다 [: [[. 을 사용하면 [[인용에 대해 걱정할 필요가 없으며 다음에 대한 [적절한 지원을 포함하여 보다 많은 연산자를 얻을 수 있습니다 ||.

if [[ $1 = "--test" || $1 = "-t" ]]
then
    echo "Testing..."
    testing="y"
else
    testing="n"
    echo "Not testing."
fi

또는 정규식을 사용할 수 있습니다.

if [[ $1 =~ ^(--test|-t) ]]
then
    echo "Testing..."
    testing="y"
else
    testing="n"
    echo "Not testing."
fi

물론 적절한 인용은 항상 이루어져야하지만 [bash 를 사용할 때 따를 이유가 없습니다 .


3

인수가 존재하는지 테스트하려면 (일반적으로, 이에 따라 조치를 수행하십시오) 다음과 같이 작동합니다.

#!/bin/bash

check=$1

if [ -z "$check" ]; then
  echo "no arguments"
else echo "there was an argument"
fi

왜 안돼 [ -z "$1" ]?
EKons

@ ΈρικΚωνσταντόπουλος이 경우 일반적으로 스크립트에서 변수를 한 번만 호출합니다. 프로 시저에서 일반적으로 한 번 이상 참조하십시오. 샘플에 프로토콜을 유지하기로 결정했습니다.
Jacob Vlijm 11

이 샘플에서는 s $check전에 한 번만 사용하는 것처럼 보이 shift므로 $1대신 사용하는 것이 좋습니다.
EKons

@ ΈρικΚωνσταντόπουλος 언급하지 않았지만, 스크립트에서 사용되는 샘플 입니다. 스크립트에서 반복해서 같은 작업을 반복해서 반복하는 것은 좋지 않습니다.
Jacob Vlijm

나는 당신이 무엇을 의미하는지 이해하지만 #!샘플을 제공 할 때 shebang을 사용하지 않는 것이 좋습니다 (코드 외부의 쉘을 설명해야 함).
EKons
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.