: (콜론) GNU Bash 내장의 목적은 무엇입니까?


336

주석 리더에 지나지 않지만 실제로 내장 된 쉘인 명령의 목적은 무엇입니까?

호출 당 약 40 % 정도 주석을 스크립트에 삽입하는 것보다 속도가 느립니다. 주석의 크기에 따라 크게 달라질 수 있습니다. 내가 볼 수있는 유일한 이유는 다음과 같습니다.

# poor man's delay function
for ((x=0;x<100000;++x)) ; do : ; done

# inserting comments into string of commands
command ; command ; : we need a comment in here for some reason ; command

# an alias for `true' (lazy programming)
while : ; do command ; done

내가 실제로 찾고있는 것은 역사적인 응용 프로그램 일 것입니다.



69
@ Caleb-나는 그 전에 2 년 전에 물었다.
amphetamachine

특정 값을 반환하는 명령은 "아무것도하지 않습니다"라고 말하고 싶지 않습니다. 기능적 프로그래밍이 "아무것도하지 않는"것으로 구성되지 않는 한. :-)
LarsH

답변:


415

역사적으로 ,의 Bourne 쉘은 없었 truefalse같은 내장 명령. true대신 :에 및 false에 비슷한 별칭이 지정되었습니다 let 0.

:true고대 Bourne에서 파생 된 포탄에 대한 이식성 보다 약간 낫습니다 . 간단한 예로, !파이프 라인 연산자 나 ||목록 연산자 를 사용하지 않는 것이 좋습니다 (일부 Bourne 쉘의 경우와 동일). 종료 상태를 기반으로 분기의 유일한 수단으로 명령문 의 else절을 남깁니다 if.

if command; then :; else ...; fi

이후 if비어 요구 then절을하고 의견이 비어로 계산하지 않는, :무 조작의 역할을한다.

요즘 (즉, 현대적인 맥락에서) 일반적으로 :또는을 사용할 수 있습니다 true. 둘 다 POSIX에 의해 지정되며 일부는 true읽기가 쉽습니다. 그러나 거기에 한 가지 흥미로운 차이점은 :소위 POSIX의입니다 내장 된 특수는 반면, trueA는 내장 된 일반 .

  • 쉘에 특수 내장 기능이 내장되어 있어야합니다. 일반 내장 기능은 "일반적으로"내장되어 있지만 엄격하게 보장되지는 않습니다. 일반적으로 대부분의 시스템의 PATH :에서 기능 이있는 정규 프로그램이 없어야 true합니다.

  • 아마도 가장 중요한 차이점은 특수 내장 기능을 사용하면 간단한 명령 평가 중 환경에서도 내장 기능에 의해 설정된 모든 변수가 ksh93을 사용하여 명령을 완료 한 후에 명령이 완료된 후에도 지속된다는 것입니다.

    $ unset x; ( x=hi :; echo "$x" )
    hi
    $ ( x=hi true; echo "$x" )
    
    $

    Zsh는 POSIX 호환 모드에서 작동 할 때를 제외하고 GNU Bash와 마찬가지로이 요구 사항을 무시하지만, 모든 주요 "POSIX sh 파생"쉘은 dash, ksh93 및 mksh를 포함하여이를 관찰합니다.

  • 또 다른 차이점은 일반 내장 기능이 호환되어야한다는 것입니다 exec-여기 Bash를 사용하여 설명하십시오.

    $ ( exec : )
    -bash: exec: :: not found
    $ ( exec true )
    $
  • POSIX는 물론 구현 관련 세부 사항이지만 :보다 빠를 수도 있음을 명시 적으로 지적합니다 true.


일반 내장 기능 과 호환 되지 않아야 함을 의미 했습니까 exec?
Old Pro

1
@OldPro : 아니오, 그는 true정식 내장이지만 정확하지는 않지만 내장 대신 exec사용 /bin/true하고 있습니다.
추후 공지가있을 때까지 일시 중지되었습니다.

1
@DennisWilliamson 난 그냥 사양이 말하는 방식으로 가고 있었다. 물론 일반 내장에는 독립형 버전이 있어야 함을 의미합니다.
ormaaj

17
+1 우수 답변. 나는 : ${var?not initialized}et al. 와 같은 변수 초기화 사용법에 여전히 주목하고 싶습니다 .
tripleee

다소 관련없는 후속 조치. 당신은 :특수 내장되어 있으며 그것에 의해 명명 된 기능이 없어야한다고 말했습니다. 그러나 가장 일반적으로 볼 수있는 포크 폭탄의 :(){ :|: & };:이름은 이름을 가진 함수의 이름을 지정하지 :않습니까?
Chong

63

변수 명령을 쉽게 활성화 / 비활성화하는 데 사용합니다.

#!/bin/bash
if [[ "$VERBOSE" == "" || "$VERBOSE" == "0" ]]; then
    vecho=":"     # no "verbose echo"
else
    vecho=echo    # enable "verbose echo"
fi

$vecho "Verbose echo is ON"

그러므로

$ ./vecho
$ VERBOSE=1 ./vecho
Verbose echo is ON

이것은 깨끗한 스크립트를 만듭니다. '#'으로는 수행 할 수 없습니다.

또한,

: >afile

'afile'이 존재하지만 길이가 0임을 보장하는 가장 간단한 방법 중 하나입니다.


20
>afile더 간단하고 동일한 효과를 얻습니다.
백작

2
쿨, 나는 유지하고있는 스크립트를 단순화하기 위해 그 $ vecho 트릭을 사용할 것이다.
BarneySchmale

5
콜론을 인용하면 어떤 이점이 vecho=":"있습니까? 가독성을 위해서만?
leoj

56

에 대한 유용한 응용 프로그램은 실제로 결과를 명령에 전달하지 않고 부작용에 매개 변수 확장 만 사용하려는 경우입니다. 이 경우 종료 상태 0 또는 1을 원하는지 여부에 따라 PE를 : 또는 false의 인수로 사용합니다 : "${var:=$1}". 예는 다음과 같습니다 . :내장되어 있기 때문에 꽤 빠릅니다.


2
산술 확장의 부작용에도 사용할 수 있습니다. : $((a += 1))( ++--연산자는 POSIX에 따라 구현할 필요가 없습니다.) bash, ksh 및 가능한 다른 쉘에서 다음을 수행 할 수도 있습니다. ((a += 1))또는 ((a++))POSIX로 지정하지 않았습니다.
pabouk

@pabouk 그렇습니다 (()). 옵션 기능으로 지정되어 있습니다. ""(( ")로 시작하는 문자 시퀀스가 ​​'$'앞에 오는 경우 셸에서 산술 확장으로 구문 분석되는 경우 확장을 구현하는 셸은"((표현)) "을 산술 표현식으로 간주 할 수 있습니다. "(((" "는 그룹화 명령 대신 산술 평가로 소개됩니다."
ormaaj

50

:블록 주석 일 수도 있습니다 (C 언어의 / * * /와 유사). 예를 들어, 스크립트에서 코드 블록을 건너 뛰려면 다음과 같이하십시오.

: << 'SKIP'

your code block here

SKIP

3
나쁜 생각. here 문서 내의 모든 명령 대체는 여전히 처리됩니다.
chepner

33
그렇게 나쁜 생각은 아닙니다. 당신은 변수 해상도를 피할 수 / 대체를 단일 인용 구분하여 여기에 문서에 : << 'SKIP'을
론도

1
IIRC에서도 \ 동일한 효과를 위해 구분 문자를 이스케이프 처리 할 수 있습니다 : <<\SKIP.
yyny

@zagpoint 파이썬이 docstring을 여러 줄 주석으로 사용하는 곳입니까?
사파이어

31

로그를 지우는 데 유용한 파일을 0 바이트로 자르려면 다음을 시도하십시오.

:> file.log

16
> file.log더 간단하고 동일한 효과를 얻습니다.
amphetamachine

55
Yah, 그러나 행복한 얼굴은 나를 위해 무엇을 하는가 :>
Ahi Tuna

23
@amphetamachine : :>더 이식성이 뛰어납니다 . my와 같은 일부 쉘 zsh은 현재 쉘에서 고양이를 자동 인스턴스화하고 명령없이 경로 재 지정이 제공되면 stdin을 청취합니다. 보다는 cat /dev/null, :훨씬 간단합니다. 이 동작은 스크립트가 아닌 대화식 쉘에서는 종종 다른 경우가 있지만 대화식으로 작동하는 방식으로 스크립트를 작성하면 복사 붙여 넣기로 디버깅하는 것이 훨씬 쉽습니다.
Caleb

2
어떻게 : > file다를 true > file현대 쉘 (문자 수와 행복한 얼굴 제외) (가정 :true동등하게 빨리)?
Adam Katz


29

다른 답변에는 언급되지 않은 두 가지 용도가 더 있습니다.

벌채 반출

이 예제 스크립트를 보자 :

set -x
: Logging message here
example_command

첫 번째 줄인에서는 set -x명령을 실행하기 전에 셸에서 명령을 인쇄합니다. 꽤 유용한 구성입니다. 단점은 echo Log message이제 일반적인 유형의 명령문이 메시지를 두 번 인쇄한다는 것입니다. 콜론 방법은 그것을 극복합니다. 원하는 것처럼 여전히 특수 문자를 이스케이프해야합니다 echo.

크론 직책

나는 cron 작업에서 다음과 같이 사용되는 것을 보았습니다.

45 10 * * * : Backup for database ; /opt/backup.sh

/opt/backup.sh매일 10:45에 스크립트를 실행하는 크론 작업입니다 . 이 기술의 장점은 /opt/backup.sh인쇄물을 출력 할 때 전자 메일 제목을 더 잘 보이게한다는 것 입니다.


기본 로그 위치는 어디에 있습니까? 로그 위치를 설정할 수 있습니까? 스크립트 / 백그라운드 프로세스 중에 stdout에서 출력을 작성하기위한 목적이 더 있습니까?
domdambrogia 2016 년

1
@domdambrogia를 사용할 때 set -x인쇄 된 명령 (같은 것을 포함하여 : foobar)은 stderr로 이동합니다.
Flimm

23

다음과 ``같이 출력을 표시하지 않고 명령을 실행하기 위해 backticks ( ) 와 함께 사용할 수 있습니다 .

: `some_command`

물론 당신은 할 수 some_command > /dev/null있지만 :-version은 다소 짧습니다.

그것은 사람들을 혼란스럽게 할 것이기 때문에 실제로 그렇게하지 않는 것이 좋습니다. 가능한 유스 케이스로 생각났습니다.


25
쉘이 출력을 버퍼링 한 다음이를 명령 행 인수 (스택 공간)로 ':'에 전달하기 때문에 명령이 몇 메가 바이트의 출력을 덤프 할 경우 안전하지 않습니다.
Juliano

15

폴리 글롯 프로그램에도 유용합니다.

#!/usr/bin/env sh
':' //; exec "$(command -v node)" "$0" "$@"
~function(){ ... }

이것은 현재 실행 쉘 스크립트 둘 다 의미 : 자바 스크립트 프로그램 ./filename.js, sh filename.jsnode filename.js모든 작업.

(확실히 약간의 이상한 사용법이지만 그럼에도 불구하고 효과적입니다.)


요청 된 일부 설명 :

  • 쉘 스크립트는 라인 단위로 평가됩니다. 그리고 exec명령, 실행할 때, 쉘 및 종료 을 대체 결과 명령으로 그것의 과정을. 즉, 쉘에 프로그램은 다음과 같습니다.

    #!/usr/bin/env sh
    ':' //; exec "$(command -v node)" "$0" "$@"
  • 단어에서 매개 변수 확장 또는 앨리어싱이 발생하지 않는 한 쉘 스크립트의 모든 단어는 의미를 변경하지 않고 따옴표로 묶을 수 있습니다. 이 수단 ':'에 해당합니다 :(우리는 자바 스크립트의 의미는 아래에 설명 달성하기 위해 여기에 따옴표로 포장 한)

  • ... 그리고 위에서 설명한 것처럼 첫 번째 줄의 첫 번째 명령은 no-op입니다 (로 번역 : //되거나 단어를 인용하는 것을 선호하는 경우) ':' '//'. //JavaScript에서와 같이 여기서 의미는 특별한 의미가 없습니다. 버려지는 의미없는 단어 일뿐입니다.)

  • 마지막으로, 세미콜론 다음에 나오는 첫 번째 행의 두 번째 명령은 프로그램 의 핵심 요소입니다. 호출되는 쉘 스크립트를 스크립트 의 나머지 부분 을 평가 하기 위해 호출 된 Node.js 프로세스로 exec대체하는 호출 입니다.

  • 한편, JavaScript에서 첫 번째 행은 문자열 리터럴 ( ':') 로 구문 분석 된 다음 삭제 된 주석으로 구문 분석 됩니다. 따라서 JavaScript의 경우 프로그램은 다음과 같습니다.

    ':'
    ~function(){ ... }

    문자열 리터럴은 그 자체로 한 줄에 있기 때문에 no-op 문이므로 프로그램에서 제거됩니다. 즉, 전체 코드 가 제거되어 프로그램 코드 (이 예에서는 본문) 남습니다 function(){ ... }.


안녕하세요, 당신은 무엇을 설명 할 수 : //;~function(){}합니까? 감사합니다:)
Stphane

1
@Stphane 고장 추가! 에 관해서 ~function(){}는 조금 더 복잡합니다. 있다 그 질문 중 어느 것도 당신이 여기에 질문으로 게시 주시기 것이 잘 충분히 설명하면 정말 그들 중 누구도 ... 내 만족을 설명 없음에도 불구하고 거기에 터치 것을, 내가있을거야 여기에 다른 답변은 새로운 질문에 대해 깊이있게 답변 해 드리겠습니다.
ELLIOTTCABLE

1
나는주의를 기울이지 않았다 node. 따라서 함수 부분은 모두 자바 스크립트에 관한 것입니다! IIFE 앞에서 단항 연산자를 사용하고 있습니다. 나는 이것이 처음부터 배쉬라고 생각했으며 실제로 게시물의 의미를 얻지 못했습니다. 난 괜찮아,«고장»을 추가하는 데 시간을 보내 주셔서 감사합니다!
Stphane

~{ No problem. (= }
ELLIOTTCABLE

12

자체 문서화 기능

:함수에 문서를 포함시키는 데 사용할 수도 있습니다 .

mylib.sh다양한 기능을 제공 하는 라이브러리 스크립트가 있다고 가정하십시오 . 라이브러리 ( . mylib.sh) 를 소싱하고 그 직후 함수를 호출 lib_function1 arg1 arg2하거나 ( ) 네임 스페이스를 어지럽히 지 않고 함수 인수 ( mylib.sh lib_function1 arg1 arg2)로 라이브러리를 호출 할 수 있습니다 .

mylib.sh --help도움말 텍스트에서 기능 목록을 수동으로 유지 관리하지 않고도 사용 가능한 기능 및 사용법 목록을 입력 하여 얻을 수 있다면 좋지 않습니까?

#! / bin / bash

# 모든 "공개"기능은이 접두사로 시작해야합니다
LIB_PREFIX = 'lib_'

# "공개"라이브러리 기능
lib_function1 () {
    :이 함수는 두 개의 인수로 복잡한 작업을 수행합니다.
    :
    : 매개 변수 :
    : 'arg1-첫 번째 인수 ($ 1)'
    : 'arg2-두 번째 인수'
    :
    : 결과 :
    : "복잡하다"

    # 실제 함수 코드는 여기서 시작합니다
}

lib_function2 () {
    : 기능 문서

    # 함수 코드는 여기
}

# 도움말 기능
--help () {
    에코 MyLib v0.0.1
    에코
    에코 사용법 : mylib.sh [function_name [args]]
    에코
    에코 사용 가능한 기능 :
    선언 -f | sed -n -e '/ ^'$ LIB_PREFIX '/, / ^} $ / {/ \ (^'$ LIB_PREFIX '\) \ | \ (^ [\ t] * : \) / {
        s / ^ \ ( '$ LIB_PREFIX'. * \) () / \ n === \ 1 === /; s / ^ [\ t] * : \? [ '\' ' "] \? / / ; s / [ '\' ' "] \?; \? $ //; p}}'
}

# 메인 코드
[ "$ {BASH_SOURCE [0]}"= "$ {0}"] 인 경우; 그때
    # 스크립트가 소스 대신 실행되었습니다
    # 요청 된 함수를 호출하거나 도움말을 표시합니다
    만약 [ "$ (type -t-"$ 1 "2> / dev / null)"= function]; 그때
        "$ @"
    그밖에
        --도움
    fi
fi

코드에 대한 몇 가지 의견 :

  1. 모든 "공개"기능은 동일한 접두사를 갖습니다. 이것들 만 사용자가 호출하고 도움말 텍스트에 나열됩니다.
  2. 자체 문서화 기능은 이전 지점에 의존하며 사용 declare -f가능한 모든 기능을 열거 한 다음 sed를 통해 해당 접두사가있는 기능 만 표시하도록 필터링합니다.
  3. 원하지 않는 확장 및 공백 제거를 방지하려면 설명서를 작은 따옴표로 묶는 것이 좋습니다. 텍스트에 아포스트로피 / 따옴표를 사용할 때도주의해야합니다.
  4. 라이브러리 접두사를 내부화하는 코드를 작성할 수 있습니다. 즉, 사용자는 입력 mylib.sh function1만하면되고 내부적으로로 변환됩니다 lib_function1. 이것은 독자에게 맡겨진 운동입니다.
  5. 도움말 기능의 이름은 "--help"입니다. 이것은 추가 호출을 코딩하지 않고도 라이브러리 호출 메커니즘을 사용하여 도움말 자체를 표시하는 편리한 (즉, 게으른) 접근 방식입니다 $1. 동시에 라이브러리를 소싱하면 네임 스페이스가 복잡해집니다. 마음에 들지 않으면 이름을 다른 것으로 변경 lib_help하거나 실제로 --help주 코드에서 인수를 확인 하고 도움말 기능을 수동으로 호출하십시오.

4

나는 스크립트 에서이 사용법을 보았고 스크립트 내에서 기본 이름을 호출하는 것이 좋은 대안이라고 생각했습니다.

oldIFS=$IFS  
IFS=/  
for basetool in $0 ; do : ; done  
IFS=$oldIFS  

...이 코드를 대체합니다. basetool=$(basename $0)


선호합니다basetool=${0##*/}
Naidu를
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.