bash에서 noop [:]의 사용 사례는 무엇입니까?


123

bash (:)에서 noop을 검색했지만 좋은 정보를 찾을 수 없었습니다. 이 연산자의 정확한 목적 또는 사용 사례는 무엇입니까?

나는 다음을 시도했고 그것은 나를 위해 다음과 같이 작동합니다.

[mandy@root]$ a=11
[mandy@root]$ b=20
[mandy@root]$ c=30
[mandy@root]$ echo $a; : echo $b ; echo $c
10
30

이 운영자의 실시간 사용 사례 또는 반드시 사용해야하는 곳을 알려주세요.



(가) 있습니다 :내장 Bourne 쉘에 존재하고 떠들썩한 파티뿐만 아니라 KSH.
ghoti


6
이것이 실제 질문이 아닌 이유는 무엇입니까? 정말 좋은 질문이라고 생각합니다. 나는 그것을 잘 사용하지만 답변을 게시 할 수 없습니다.
Steven Lu

답변:


175

역사적인 이유로 더 많이 있습니다. 내장 콜론 :은 정확히 true. true예를 들어 무한 루프에서 반환 값이 중요 할 때 사용하는 것이 일반적입니다 .

while true; do
  echo 'Going on forever'
done

:셸 구문에 명령이 필요하지만 할 일이 없을 때 사용하는 것이 일반적 입니다.

while keep_waiting; do
  : # busy-wait
done

:모든 내장 날짜받는 방식을 다시 톰슨 쉘 , 그것은했다 현재유닉스 버전 6 . :Thompson 쉘의 goto진술에 대한 라벨 표시기였습니다 . 레이블은 텍스트가 될 수 있으므로 :(더있을 경우 코멘트 지표로 두 배로 goto comment하고 : comment효과적으로 주석 없음). Bourne 쉘은 하지 않았다 goto하지만 유지 :.

일반적인 관용구가 사용하는 것을 :입니다 : ${var=VALUE}, 어떤 세트 varVALUE이 설정되지 않은이었고, 경우 아무것도하지 않는 경우 var이미 설정되었다. 이 구조는 변수 대체의 형태로만 존재하며이 변수 대체는 어떤 식 으로든 명령의 일부 여야합니다. no-op 명령은 훌륭하게 작동합니다.

콜론 내장어떤 용도로 사용됩니까? .


11
좋은 요약입니다. 또한 원래 Bourne 쉘은 #주석 (또는 #!/bin/shshebangs)에 사용하지 않았습니다 . :: 자신의 의견에 별의 좋은 상자를 만든 순진한 프로그래머 발생하다 코멘트를 소개 명령과 비애 : ****(,, 악화 또는 : * * *).
Jonathan Leffler 2013 년

3
@JonathanLeffler : 부끄럽지만 이해가 안 돼요. 어떻게 : * * *될까요?
DevSolar 2014

7
:은 명령 이기 때문에 쉘은 인수를 :무시하는 것을 발견하기 전에 인수를 처리 해야합니다. 대부분 *은 현재 디렉토리에있는 파일 목록으로 확장 할 때 쉘이 추가 작업을 수행하도록 만드는 것입니다 . 실제로 스크립트 작동 방식에는 영향을주지 않습니다.
chepner 2014

파일이 많은 디렉토리에서 실행되어 glob 확장이 명령 길이 제한을 초과하면 스크립트가 실패 할 수 있다고 생각합니다. 당신이 가지고 있다면 아마 set -e. 어쨌든, 잘하면 우리는 단지 사용 동의 할 수있다 #:
잭 오코너

2
while : ; do ... ; done빠르고 더러운 무한 루프를 원한다면 가끔 사용 합니다. (보통 sleep루프에 a 가 있고 Ctrl-C를 눌러 죽입니다.)
Keith Thompson

21

모든 코드를 주석 처리 할 때 if 문에 사용합니다. 예를 들어 테스트가 있습니다.

if [ "$foo" != "1" ]
then
    echo Success
fi

그러나 그 안에 포함 된 모든 것을 일시적으로 주석 처리하고 싶습니다.

if [ "$foo" != "1" ]
then
    #echo Success
fi

이로 인해 bash가 구문 오류를 제공합니다.

line 4: syntax error near unexpected token `fi'
line 4: `fi'

Bash는 빈 블록 (WTF)을 가질 수 없습니다. 따라서 no-op을 추가합니다.

if [ "$foo" != "1" ]
then
    #echo Success
    :
fi

또는 no-op을 사용하여 줄을 주석 처리 할 수 ​​있습니다.

if [ "$foo" != "1" ]
then
    : echo Success
fi

12

set- ethen 을 사용 하면 실패가 발생해도 스크립트를 종료 하지 않는|| : 좋은 방법입니다 (명시 적으로 통과하게 함).


1
특정 쉘 스크립트 호출 응용 프로그램에 유용하다는 것을 알았습니다. 예를 들어 Mac의 Automator는 오류가 발생하면 종료되고 이유를 알려주지 않습니다. 그러나 || :나중에 오류를 직접 처리하면 exit 0디버깅 중에 모든 stdout 및 stderr를 앱 창에 표시 할 수 있습니다. { foo ... 2>&1; } || :더 복잡한 트랩과 if-thens를 설정하는 것보다 훨씬 간단한 것을 고려하십시오 .
Beejor

7

:성공하지만 아무것도 수행하지 않는 명령을 제공하는 데 사용 합니다. 이 예에서 "verbosity"명령은로 설정하여 기본적으로 해제됩니다 :. 'v'옵션은이를 켭니다.

#!/bin/sh
# example
verbosity=:                         
while getopts v OPT ; do          
   case $OPT in                  
       v)        
           verbosity=/bin/realpath 
       ;;
       *)
           exit "Cancelled"
       ;;             
   esac                          
done                              

# `$verbosity` always succeeds by default, but does nothing.                              
for i in * ; do                   
  echo $i $($verbosity $i)         
done                              

$ example
   file

$ example -v
   file /home/me/file  

엄밀히 말하면 변수에 값을 할당하는 것은 "무언가를 수행"하는 것이므로 case 문에 오류가 발생하지 않는 이유입니다.
qodeninja

@qodeninja : 아무도 변수 할당이 "아무것도하지 않았다"고 주장하지 않았습니다. 요점은 $(verbosity $i)나중에 (그리고 조건부로) 아무것도하지 않는다는 것입니다.
궤도의 가벼운 경주

6

alias인수 무시

어떤 경우에는 인수를받지 않는 별칭을 원합니다. 다음을 사용하여 수행 할 수 있습니다 :.

> alias alert_with_args='echo hello there'

> alias alert='echo hello there;:'

> alert_with_args blabla
hello there blabla

> alert blabla
hello there

반대 투표자는 아니지만이 답변은 :불행히도 작동 방식을 보여주지 않습니다 . 제공 한 예제가 중복 된 것 같습니다.
qodeninja jul.

2
문제는 작동 방식이 아니라 사용 사례 입니다. 내 대답이 stackoverflow.com/a/37170755/6320039 와 약간 비슷하다는 것은 사실 입니다. 그러나 실제로는 동일한 사용 사례가 아닙니다. 내 대답을 개선하기 위해 기꺼이 것입니다하지만 난 정말 krnow하지 않는 방법 여기 ..
ULYSSE BN

1
이것은 약간 펑키합니다. 코너 케이스입니다.하지만 여전히 꽤 흥미롭고 뒷주머니에 넣는 영리한 트릭이 될 수 있습니다.
Mike S

2
동일은 달성 할 수#
조이 Hewll

2
@ZoeyHewll, 정답이 아닙니다. 별칭은 어떤 종류의 실행 전에 텍스트 로 대체 되기 때문에 별칭을 사용 #하면 동일한 줄에서 구문 상 뒤에 오는 모든 항목이 무시됩니다. 이것은 (고려 정말 다른 my_alias arg ; other_command, 반대로, 또는 my_alias arg1 {BACKSLASH}{NEWLINE} arg2), 당신이 그것을 구문 오류를 (무엇을 추측의 원인이 될 수 원하는 아마하지 while my_alias ; do true ; donewhile true ; do my_alias ; done할 것입니다).
Maëlan

4

한 가지 용도는 여러 줄 주석으로 사용하거나 here 파일과 함께 사용하여 테스트 목적으로 코드의 일부를 주석 처리하는 것입니다.

: << 'EOF'

This part of the script is a commented out

EOF

EOF내부 코드가 평가되지 않도록 따옴표를 사용하는 것을 잊지 마십시오 $(foo). 또한 같은 직관적 인 터미네이터 이름을 사용할 가치가있다 NOTES, SCRATCHPAD또는 TODO.


멋진 트릭! 특히 하드 랩핑 할 때 수십 개의 "#"이 필요한 스크래치 노트 및 코드의 경우. 부작용은 주석 줄과 달리 일부 구문 하이 라이터가 heredocs를 무시하고 일반 코드 (또는 최소한 일반 텍스트)처럼 색상을 지정한다는 것입니다. 주석 처리 된 코드를 검토하거나 네온 주석 색상으로 단락에서 눈을 절약하는 데 유용 할 수 있습니다. 유일한주의 사항은 구문이 고유하고 혼동을 일으킬 수 있으므로 이러한 블록은 공유 코드에서 주석으로 표시되어야한다는 것입니다. 다시 말하지만, 이것은 우리가 이야기하고있는 껍데기이며, 혼란의 가능성은 체계적입니다.
Beejor

3

내 두 명.

POD 주석 삽입

의 매우 펑키 한 응용 프로그램은 bash 스크립트에 POD 주석:포함 하여 man 페이지를 빠르게 생성 할 수 있도록하는 것입니다. 물론, 결국 Perl에서 전체 스크립트를 다시 작성합니다 ;-)

런타임 함수 바인딩

이것은 런타임에 함수를 바인딩하기위한 일종의 코드 패턴입니다. Fi, 특정 플래그가 설정된 경우에만 디버깅 기능이 있습니다.

#!/bin/bash
# noop-demo.sh 
shopt -s expand_aliases

dbg=${DBG:-''}

function _log_dbg {
    echo >&2 "[DBG] $@"
}

log_dbg_hook=':'

[ "$dbg" ] && log_dbg_hook='_log_dbg'

alias log_dbg=$log_dbg_hook


echo "Testing noop alias..."
log_dbg 'foo' 'bar'

당신은 얻을 :

$ ./noop-demo.sh 
Testing noop alias...
$ DBG=1 ./noop-demo.sh 
Testing noop alias...
[DBG] foo bar

2

때때로 no-op 절은 코드를 더 읽기 쉽게 만들 수 있습니다.

그것은 의견의 문제 일 수 있지만 여기에 예가 있습니다. 두 개의 유닉스 경로를 사용하여 작동하는 함수를 만들었다 고 가정 해 보겠습니다. 한 경로에서 다른 경로로 cd하는 데 필요한 '경로 변경'을 계산합니다. 경로가 모두 '/'로 시작해야하거나 둘 다 시작하지 않아야한다는 제한을 함수에 적용합니다.

function chgpath() {
    # toC, fromC are the first characters of the argument paths.
    if [[ "$toC" == / && "$fromC" == / ]] || [[ "$toC" != / && "$fromC" != / ]]
    then
        true      # continue with function
    else
        return 1  # Skip function.
    fi

일부 개발자는 no-op을 제거하고 싶지만 조건부 부정을 의미합니다.

function chgpath() {
    # toC, fromC are the first characters of the argument paths.
    if [[ "$toC" != / || "$fromC" == / ]] && [[ "$toC" == / || "$fromC" != / ]]
    then
        return 1  # Skip function.
    fi

이제-내 의견으로는-함수 수행을 건너 뛰고 싶은 조건이 if 절에서 명확하지 않습니다. no-op을 제거하고 명확하게 수행하려면 if 절을 함수에서 제거해야합니다.

    if [[ "$toC" == / && "$fromC" == / ]] || [[ "$toC" != / && "$fromC" != / ]]
    then
        cdPath=$(chgPath pathA pathB)   # (we moved the conditional outside)

더 좋아 보이지만 여러 번 우리는 이것을 할 수 없습니다. 함수 내에서 확인이 수행되기를 원합니다.

그래서 얼마나 자주 이런 일이 발생합니까? 자주는 아닙니다. 아마도 일년에 한두 번. 충분히 자주 발생하므로 알고 있어야합니다. (언어에 관계없이) 내 코드의 가독성을 향상 시킨다고 생각할 때 나는 그것을 사용하는 것을 주저하지 않습니다.


3
당신의 목적에 대한 질문에 대답하는 경우 :, 당신은 사용해야 :하지, true이 질문에 대해. 즉 여기에 조건을 부정하는 가장 쉬운 방법은 하나를 사용하는 것입니다 말했다 [[ ... ]]명령과 함께 접두사 !: if ! [[ ( ... && ... ) || ( ... && ... ) ]]; then.
chepner 2014

1
아, 아주 좋아. 내 대답에 찬성 투표를해야 겠어. 흠 .... 저는 여전히 no-op 절을 사용해야하는 예를 생각하고 있습니다. 이것은 내가 생각 해낸 최고입니다.
Bitdiot 2014

: ${...=...}.NET보다 덜 어색해 보이지만 실제로 는 이전 버전과의 호환성을 위해 유지됩니다 true ${...=...}. 일부는 간결함을 선호 while :; do할 수도 while true; do있습니다.
chepner 2014

2

이 답변 과 다소 관련 있으므로이 no-op은 다중 언어 스크립트 를 해킹하는 데 다소 편리합니다 . 예를 들어, 다음은 bash와 vimscript 모두에 유효한 주석입니다.

":" #    this is a comment
":" #    in bash, ‘:’ is a no-op and ‘#’ starts a comment line
":" #    in vimscript, ‘"’ starts a comment line

물론 우리도 true똑같이 사용했을 수도 있지만 :, 관련없는 영어 단어가 아닌 구두점 기호는 그것이 구문 토큰이라는 것을 분명히합니다.


누군가가 다국어 스크립트를 작성하는 것과 같이 까다로운 일을하는 이유관해서 는 (멋진 것 외에도) : 일반적으로 file을 X참조하는 파일 과 함께 여러 다른 언어로 여러 스크립트 파일을 작성하는 상황에서 도움 이됩니다 Y.

이러한 상황에서 두 스크립트를 단일 X다중 언어 파일에 결합 하면 경로를 결정하는 작업을 피할 수 있습니다 Y(단순히 "$0"). 더 중요한 것은 프로그램을 이동하거나 배포하는 것이 더 편리하다는 것입니다.

  • 일반적인 예입니다. shebangs에는 잘 알려진 오랜 문제가 있습니다. 대부분의 시스템 (Linux 및 Cygwin 포함)은 하나의 인수 만 인터프리터에 전달할 수 있습니다. 다음 shebang :

    #!/usr/bin/env interpreter --load-libA --load-libB

    다음 명령을 실행합니다.

    /usr/bin/env "interpreter --load-libA --load-libB" "/path/to/script"

    의도 한 것이 아닙니다.

    /usr/bin/env interpreter --load-libA --load-libB "/path/to/script"

    따라서 다음과 같은 래퍼 스크립트를 작성하게됩니다.

    #!/usr/bin/env sh
    /usr/bin/env interpreter --load-libA --load-libB "/path/to/script"

    이것은 다 색체가 무대에 들어가는 곳입니다.

  • 더 구체적인 예입니다. 저는 한때 Vim을 호출하는 bash 스크립트를 작성했습니다. Vim에 추가 설정을 제공해야했는데 옵션으로 수행 할 수 있습니다 --cmd "arbitrary vimscript command here". 그러나 그 설정은 상당했기 때문에 문자열에 인라이닝하는 것은 끔찍했습니다 (가능하다면). 따라서 더 나은 해결책은 일부 구성 파일의 extenso작성한 다음 Vim이 -S "/path/to/file". 따라서 나는 다국어 bash / vimscript 파일로 끝났습니다.


1

또한 기본 변수를 정의하기 위해 스크립트를 사용했습니다.


: ${VARIABLE1:=my_default_value}
: ${VARIABLE2:=other_default_value}
call-my-script ${VARIABLE1} ${VARIABLE2}

0

다른 명령의 성공에 연결하려는 명령이 있다고 가정합니다.

cmd="some command..."
$cmd
[ $? -eq 0 ] && some-other-command

하지만 이제 명령을 조건부로 실행하고 실행될 명령을 표시하려고합니다 (드라 이런).

cmd="some command..."
[ ! -z "$DEBUG" ] && echo $cmd
[ -z "$NOEXEC" ] && $cmd
[ $? -eq 0 ] && {
    cmd="some-other-command"
    [ ! -z "$DEBUG" ] && echo $cmd
    [ -z "$NOEXEC" ] && $cmd
}

따라서 DEBUG 및 NOEXEC를 설정하면 두 번째 명령이 표시되지 않습니다. 이는 첫 번째 명령이 실행되지 않기 때문입니다 (NOEXEC가 비어 있지 않기 때문에).하지만 그 사실을 평가하면 1이 반환됩니다. 즉, 하위 명령이 실행되지 않는다는 의미입니다 (하지만 테스트 실행이기 때문에 실행하고 싶음). 이 문제를 해결하려면 noop을 사용하여 스택에 남아있는 종료 값을 재설정 할 수 있습니다.

[ -z "$NOEXEC" ] && $cmd || :
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.