쉘 스크립트에서 : 명령의 유틸리티는 무엇입니까?


27

쉘 스크립팅의 주석에 대한이 질문에 대한 대답에서는 :명시 적으로 아무것도 수행하지 않는 null 명령 임을 나타냅니다 (그러나 주석에는 사용되지 않아야 함).

전혀 아무것도하지 않는 명령의 유틸리티는 무엇입니까?



2
여기에 더 나은 답변이있는 이 질문 을 참조 하십시오 . 즉 :, 내장형이어야하지만 true변수의 범위에 영향을주는 것은 아닙니다
Old Pro

2
명시 적으로 아무 것도 우아하게 하지 않습니다 .
mikeserv

답변:


19

나는 일반적으로 true루프에서 사용합니다 . 나는 그것이 더 분명하다고 생각합니다.

while true; do
    ...
done

내가 찾은 한 가지 점 :은 무언가를 일치시켜야하지만 실제로는 아무것도하고 싶지 않다면 경우에 대한 진술입니다. 예를 들면 다음과 같습니다.

case $answer in
    ([Yy]*) : ok ;;
    (*)     echo "stop."; exit 1 ;;
esac

3
동의한다. true조건, :NOP.
jw013

1
bash는 허용 case a in a ) ;; esac합니다. 이것을 받아들이지 않는 껍질이 있습니까?
Kaz

@Kaz는 다음에 따라 POSIX 쉘 문법 , case ${var} in value);; *) do_something;; esac수용. :명령은 비어있는 경우에 필요하지 않습니다.
Richard Hansen

12

원래는 C 컴파일 된 프로그램과 달리 Bourne 쉘 프로그램인지 판별하는 데 사용되었습니다. 이것은 shebang 이전과 여러 스크립트 언어 (csh, perl) 이전이었습니다. 다음과 같이 시작하여 스크립트를 계속 실행할 수 있습니다 :.

$ echo : > /tmp/xyzzy
$ chmod +x /tmp/xyzzy
$ ./xyzzy

일반적으로 $SHELL(또는 /bin/sh) 에 대해 스크립트를 실행합니다 .

그 이후로 주요 용도는 인수를 평가하는 것입니다. 나는 여전히 사용합니다 :

: ${EDITOR:=vim}

스크립트에서 기본값을 설정합니다.


11

: 내부에서 종료해야하는 루프를 작성하는 데 유용합니다.

while :
do
    ...stuff...
done

break또는 exit호출 하지 않으면 쉘이 종료 신호를 수신 하지 않는 한 영원히 실행됩니다 .


3
나는 그 느낌 while true; do ...; done보다 더 독자와 통신의 의도를while :; do ...; done
리차드 한센

9

쉘 스크립팅에서 "unless"문을 원할 경우, "not"조건을 사용하여 테스트 중 일부를 구피 할 수 있거나 true 절에서 ':'를 사용하고 실제 코드는 false로 절.

if [ some-exotic-condition ]
then
    :
else
    # Real code here
fi

"이국적 조건"은 부정하고 싶지 않은 것이거나 "부정적 논리"를 사용하지 않는 경우 훨씬 더 명확합니다.


1
또한 조건을 바꾸는 방법을 찾는 것보다 빈 분기에 autoconf대한 기본값을 추가하는 것이 훨씬 쉽기 때문에 생성 된 스크립트에 표시됩니다 :.
Dietrich Epp

2
나는 !앞에서 [ some-exotic-condition ]바보를 짓는 것이 얼마나 구피 : else인지 알 수 없지만, 구피가 아닌 후에 불필요 합니다.
Kaz

@Kaz는 좋은 지적이 있습니다. 이국적인 조건을 찾는 것은 기껏해야 어렵다는 것을 명심하십시오. 모든 것을 부정해야한다면 그것은 한 가지 일이지만 조건을 덜 명확하게 만들 수 있습니다. '!' 전체 조건을 부정합니까, 아니면 첫 번째 용어입니까? 때때로 ':'true 절을 사용하는 것이 가장 좋습니다.
브루스 에디 거

!토큰 전체 명령 파이프 요소를 부정. while ! grep ... ; do ... done 또는 if ! [ ... ] ; then ... fi. 기본적으로 test/[]구문 외부 입니다. 참조 : pubs.opengroup.org/onlinepubs/9699919799/utilities/…
Kaz

5

빈 줄의 명령을 허용하지 않는 쉘 문법의 결함으로 인해 줄을 주석 처리하면 구문 오류가 발생하는 상황에서 줄을 일시적으로 주석 처리하기 위해 # 문자 외에도 이것을 사용했습니다. :

if condition ; then
    :# temporarily commented out command
fi

:이 없으면 구문 오류 인 명령 시퀀스가 ​​누락됩니다.


4

:유용하다고 생각되는 두 가지 경우가 있습니다 .

기본 변수 할당

#!/bin/sh

# set VAR to "default value" if not already set in the environment
: "${VAR=default value}"

# print the value of the VAR variable.  Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR}"

이것은 쉘 스크립트 사용자가 스크립트를 편집하지 않고 설정을 무시할 수있는 편리한 방법입니다. 그러나 사용자에게 내 보낸 환경에서 사용하는 변수가 우연히있을 경우 예기치 않은 동작의 위험이 발생하지 않기 때문에 명령 줄 인수 가 더 좋습니다. 다음은 사용자가 설정을 재정의하는 방법입니다.

VAR="other value" ./script

${VAR=value}구문은 세트로 말한다 VARvalue경우 VAR아직 설정되어 있지 않은 경우, 변수의 값으로 확장합니다. 우리는 아직 변수의 값에 신경 쓰지 않기 때문에 변수 :를 버릴 수 있는 no-op 명령 에 인수로 전달됩니다 .

비록 :, 확장이 쉘에 의해 수행된다 (안 무 연산 명령입니다 :실행하기 전에 명령!) :(해당하는 경우) 변수 할당이 계속 발생 있도록 명령.

true또는 대신 다른 명령 을 사용하는 것도 :좋지만 의도가 덜 명확하기 때문에 코드를 읽기가 더 어려워집니다.

다음 스크립트도 작동합니다.

#!/bin/sh

# print the value of the VAR variable.  Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR=default value}"

그러나 위의 내용은 유지하기가 훨씬 어렵습니다. 사용중인 라인 ${VAR}이 해당 printf라인 위에 추가 되면 기본 할당 확장을 이동해야합니다. 개발자가 해당 과제를 옮기는 것을 잊어 버린 경우 버그가 발생합니다.

빈 조건부 블록에 넣을 내용

빈 조건부 블록은 일반적으로 피해야하지만 때로는 유용합니다.

if some_condition; then
    # todo:  implement this block of code; for now do nothing.
    # the colon below is a no-op to prevent syntax errors
    :
fi

어떤 사람들은 빈 if블록 이 비어 있으면 테스트를 부정하는 것보다 코드를 쉽게 읽을 수 있다고 주장합니다 . 예를 들면 다음과 같습니다.

if [ -f foo ] && bar || baz; then
    :
else
    do_something_here
fi

다음보다 읽기 쉽습니다.

if ! [ -f foo ] || ! bar && ! baz; then
    do_something_here
fi

그러나 빈 참 블록보다 나은 몇 가지 대안이 있다고 생각합니다.

  1. 조건을 함수에 넣으십시오.

    exotic_condition() { [ -f foo ] && bar || baz; }
    
    if ! exotic_condition; then
        do_something_here
    fi
  2. 부정하기 전에 조건을 중괄호 안에 넣거나 괄호 안에 괄호를 사용하면 서브 쉘 프로세스가 생성되고 서브 쉘 내부 환경에 대한 변경 사항이 서브 쉘 외부에 표시되지 않습니다.

    if ! { [ -f foo ] && bar || baz; } then
        do_something_here
    fi
  3. ||대신에 사용하십시오 if:

    [ -f foo ] && bar || baz || {
        do_something_here
    }

    반응이 주장 조건과 같은 간단한 단일 라이너 일 때이 접근법을 선호합니다.

    log() { printf '%s\n' "$*"; }
    error() { log "ERROR: $*" >&2; }
    fatal() { error "$@"; exit 1; }
    
    [ -f foo ] && bar || baz || fatal "condition not met"

1

고대 버전의 UNIX에있는 이전 pre-bourne 쉘에서이 :명령은 원래 레이블을 지정하기위한 것입니다 goto(이 레이블은 레이블이있는 위치로 입력을 전달하는 별도의 명령이므로 레이블은 쉘은 알고있다. if또한 별도의 명령이었다.) 주석 구문 ( #백 스페이스에 사용됨)이 있기 전에 주석 에 사용되었으며, 요즘에는 호환성만큼이나 중요하다.


0

아무것도하지 않는 명령문으로 사용하는 것 외에도, 단일 명령문을 :에 대한 인수로 바꿔 주석을 달 수 있습니다.


: echo write this line > myfile여전히 빈 파일을 생성 하므로 주석이 아닙니다 .
Arcege

5
질문의 링크에서 설명했듯이 적절한 주석 달기 메커니즘 :아닙니다 .
jw013
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.