에코 대 <<< 또는 Bash Award에서 에코의 쓸모없는 사용?


19

지금 쯤 의 쓸모없는 사용 cat상은 매우 잘 알려진, 그리고의 언급도 거기에있다 의 쓸모없는 사용echo (이 질문에 대한 관련되지 않음). " echoBash Award에서 쓸모없는 사용"이 필요한지 궁금합니다 . 비과학적인 측정에 따르면 파이프는 heredocs 및 herestrings보다 훨씬 느리게 보입니다.

  • Heredocs :

    for reps in 1 2 3
    do
        time for i in {1..1000}
        do
            cat <<'END'
    test string
    END
        done > /dev/null
    done
    
    real    0m1.786s
    user    0m0.212s
    sys     0m0.332s
    
    real    0m1.817s
    user    0m0.232s
    sys     0m0.332s
    
    real    0m1.846s
    user    0m0.256s
    sys     0m0.320s
    
  • Herestrings

    for reps in 1 2 3
    do
        time for i in {1..1000}
        do
            cat <<< 'test string'
        done > /dev/null
    done
    
    real    0m1.932s
    user    0m0.280s
    sys     0m0.288s
    
    real    0m1.956s
    user    0m0.248s
    sys     0m0.348s
    
    real    0m1.968s
    user    0m0.268s
    sys     0m0.324s
    
  • 리디렉션

    for reps in 1 2 3
    do
        time for i in {1..1000}
        do
            echo 'test string' | cat
        done > /dev/null
    done
    
    real    0m3.562s
    user    0m0.416s
    sys     0m0.548s
    
    real    0m3.924s
    user    0m0.384s
    sys     0m0.604s
    
    real    0m3.343s
    user    0m0.400s
    sys     0m0.552s

일반적으로 heredocs와 herestrings는 속도가 거의 같으며 (여러 테스트에서 하나의 데이터 세트 임) 리디렉션이 50 % 이상 느립니다. 내가 잘못 이해하고 있습니까, 아니면 Bash에서 표준 입력을 읽는 명령의 일반적인 규칙으로 사용할 수 있습니까?


4
나는 확실히 당신에게 "무용 한 사용 seq"상을 허락 할 것입니다 ;-)
Chris Down

2
당신이 중 하나를 비교해야합니다 cat <<ENDcat <<< "test string"echo "test string" | cat또는 cat <<'END'cat <<< 'test string'대는 echo 'test string' | cat확장이 문자열에 쉘에 의해 수행의 동일한 금액을 가지고 있습니다.
manatwork

@ChrisDown Derp. 나는 항상 그 것을 잊습니다. 감사!
l0b0

@manatwork 감사합니다, 고정 및 업데이트 된 타이밍.
l0b0

호기심 만 있다면 그 담당자는 무엇입니까? 원래 $ reps 번 반복하려는 의도가 아니 었습니까 $(seq $reps)?
manatwork

답변:


11

먼저 성능에 집중하자. 데비안 스퀴즈를 실행하는 유휴 x86_64 프로세서에서 약간 다른 프로그램에 대한 벤치 마크를 실행했습니다.

herestring.bashherestring을 사용하여 입력 행을 전달하십시오.

#! /bin/bash
i=0
while [ $i -lt $1 ]; do
  tr a-z A-Z <<<'hello world'
  i=$((i+1))
done >/dev/null

heredoc.bashheredoc을 사용하여 입력 줄을 전달하십시오.

#! /bin/bash
i=0
while [ $i -lt $1 ]; do
  tr a-z A-Z <<'EOF'
hello world
EOF
  i=$((i+1))
done >/dev/null

echo.bash, echo및 파이프를 사용하여 입력 라인을 전달합니다.

#! /bin/bash
i=0
while [ $i -lt $1 ]; do
  echo 'hello world' | tr a-z A-Z
  i=$((i+1))
done >/dev/null

비교를 위해 ATT ksh93 및 대시 ( herestring.bash대시에는 herestring이 없기 때문에 제외)에서 스크립트의 시간을 정했습니다 .

다음은 3 회 중위입니다.

$ time bash ./herestring.bash 10000
./herestring.bash 10000  0.32s user 0.79s system 15% cpu 7.088 total
$ time ksh ./herestring.bash 10000
ksh ./herestring.bash 10000  0.54s user 0.41s system 17% cpu 5.277 total
$ time bash ./heredoc.bash 10000
./heredoc.bash 10000  0.35s user 0.75s system 17% cpu 6.406 total
$ time ksh ./heredoc.bash 10000  
ksh ./heredoc.sh 10000  0.54s user 0.44s system 19% cpu 4.925 total
$ time sh ./heredoc.bash 10000  
./heredoc.sh 10000  0.08s user 0.58s system 12% cpu 5.313 total
$ time bash ./echo.bash 10000
./echo.bash 10000  0.36s user 1.40s system 20% cpu 8.641 total
$ time ksh ./echo.bash 10000
ksh ./echo.sh 10000  0.47s user 1.51s system 28% cpu 6.918 total
$ time sh ./echo.sh 10000
./echo.sh 10000  0.07s user 1.00s system 16% cpu 6.463 total

결론 :

  • heredoc은 herestring보다 빠릅니다.
  • echo그리고 파이프는 눈에 띄지 만 빠르지는 않습니다. (이것은 장난감 프로그램이라는 것을 명심하십시오. 실제 프로그램에서, 대부분의 처리 시간은 tr전화가 여기 서 의미 하는 시간이 될 것 입니다.)
  • 속도를 원한다면 bash를 버리고 대신 대시 또는 더 나은 ksh를 호출하십시오. Bash의 기능은 상대적 속도 저하를 보완하지 않지만 ksh에는 기능과 속도가 모두 있습니다.

성능 외에도 명확성과 이식성이 있습니다. <<<ksh93 / bash / zsh 확장자는 echo … |or 보다 덜 알려져 <<있습니다. ksh88 / pdksh 또는 POSIX sh에서는 작동하지 않습니다.

<<<논란의 여지가 분명한 유일한 곳 은 heredoc 안에 있습니다.

foo=$(tr a-z A-Z <<<'hello world')

vs

foo=$(tr a-z A-Z <<'EOF'
hello world
EOF
)

(대부분의 쉘은을 포함하는 줄의 끝에서 괄호를 닫는 데 대처할 수 없습니다 <<EOF.)


2
<<<에서 제공 rc하고, 처음으로 본쉘 같은 세계에 오게됐다 zsh. rc뒤에 줄 바꿈을 추가 할 수 있지만 모든하지 않았다 bash, zsh그리고 ksh93AFAICT을한다. rc하지만, 거기에 파이프를 사용 bash, zshksh93heredocs에 대한 같은 임시 파일을 사용합니다.
Stéphane Chazelas

@StephaneChazelas 죄송합니다. 감사합니다. 이것은 <<<훨씬 덜 유용합니다.
Gilles 'SO- 악의를 그만두십시오

또한 프로세스를 포크하지 않아도되는 "foo"를 포함하는 임시 파일을 효과적으로 생성 zsh하도록 최적화되었습니다 . =(<<<foo)=(echo foo)
Stéphane Chazelas

또한 pdksh에 포함 되지 않는다고 언급 할 것 <<<입니다.
kurtm

@kurtm“ksh88 / pdksh 또는 POSIX sh에서는 작동하지 않습니다.”
Gilles 'SO-Stop

6

heredocs를 사용하는 또 다른 이유는 충분하지 않은 경우 스트림을 소비하지 않으면 에코가 실패 할 수 있기 때문입니다. bash ' pipefail옵션을 고려하십시오 .

set -o pipefail
foo=yawn
echo $foo | /bin/true ; echo $?  # returns 0

/bin/true표준 입력을 소비하지 않지만 echo yawn그럼에도 완료됩니다. 그러나 echo에 많은 양의 데이터를 인쇄하도록 요청하면 완료 될 때까지 완료되지 않습니다 true.

foo=$(cat /etc/passwd)
# foo now has a fair amount of data

echo $foo | /bin/true ; echo $?  # returns 0 sometimes 141
echo $foo$foo$foo$foo | /bin/true ; echo $?  # returns mostly 141

141은 SIGPIPE (128 + 13)입니다. bash는 bash (1)에 따라 추가되므로 128이 추가됩니다.

치명적 신호 N에서 명령이 종료되면 bash는 종료 상태로 128 + N 값을 사용합니다.

Heredocs에는이 문제가 없습니다.

/bin/true <<< $foo$foo$foo$foo ; echo $?  # returns 0 always

고마워,이 특별한 뉘앙스가 kvm 호스트보다 Amazon 서버에서 무작위로 임의의 장소에서 스크립트가 간헐적으로 실패하게 만들었지 만 여전히 실패하기 어려운 곳에서 때때로 실패했습니다. pipefail기본값이 꺼져 있는 것이 좋습니다 !
mogsie

2
아, 나는 pipefail모든 스크립트의 맨 위에서 활성화 합니다. 모든 오류를 피하십시오!
l0b0

@ l0b0 흠. 어쩌면 j.mp/safebash에 pipefail을 추가 할 것입니다 . 개발 중에 모든 오류가 발생했습니다.
Bruno Bronosky

2

echo를 사용하려는 한 가지 이유는 heredocs 및 herestrings 끝에 추가되는 줄 바꿈 문자를 제어하는 ​​것입니다.

3 자 foo길이는 3입니다.

$ echo -n foo | wc -c
3

그러나 3 자 herestring은 4 자입니다.

$ wc -c <<< foo
4

세 글자 heredoc도 :

$ wc -c << EOF
foo
EOF
4

네 번째 문자는 개행 0x0a문자입니다.

어쨌든 이것은 서브 쉘에서 출력을 잡을 때 bash가 이러한 개행 문자를 제거하는 방식에 마술처럼 맞습니다.

여기에 네 개의 문자를 반환하는 명령은 다음과 같습니다 foo\n. '\ n'은 echo에 의해 추가되며 -n옵션 을 지정하지 않으면 항상 줄 바꿈 문자를 추가합니다 .

$ echo foo
foo
$ echo foo | wc -c
4

그러나 이것을 변수에 할당하면 echo에 의해 추가 된 후행 줄 바꿈이 제거됩니다.

$ foo=$(echo foo)
$ echo "$foo" # here, echo adds a newline too.
foo

따라서 파일과 변수를 혼합하여 계산에 사용하는 경우 (예 : heredocs 또는 herestrings는 줄 바꿈을 추가하므로 사용할 수 없습니다.

foo=abc
echo -n 'abc' > something.txt
if [ $(wc -c <<< "$foo") -eq $(wc -c < something.txt) ] ; then
  echo "yeah, they're the same!"
else
  echo "foo and bar have different lengths (except, maybe not)"
fi

if 문을 읽도록 변경하면

if [ $(echo -n "$foo" | wc -c) -eq $(wc -c < something.txt) ] ; then

그런 다음 테스트가 통과됩니다.

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