![echo 및 <<<, 아니면 Bash Award에서 에코를 쓸모 없게 사용합니까?](https://linux55.com/image/44095/echo%20%EB%B0%8F%20%26lt%3B%26lt%3B%26lt%3B%2C%20%EC%95%84%EB%8B%88%EB%A9%B4%20Bash%20Award%EC%97%90%EC%84%9C%20%EC%97%90%EC%BD%94%EB%A5%BC%20%EC%93%B8%EB%AA%A8%20%EC%97%86%EA%B2%8C%20%EC%82%AC%EC%9A%A9%ED%95%A9%EB%8B%88%EA%B9%8C%3F.png)
지금까지cat
보상은 소용없다잘 알려져 있고 언급되기도 함쓸모없는 사용echo
(이 질문과 관련이 없습니다). "Bash에서 쓸모없는 사용 상"이 있어야 하는지 궁금합니다 echo
. 일부 매우 비과학적인 측정에 따르면 파이프는 heredocs 및 herestrings보다 훨씬 느린 것 같습니다.
상속 문서:
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
허스트
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에서 표준 입력을 읽는 명령에 대한 일반 규칙으로 사용될 수 있습니까?
답변1
먼저, 성능에 중점을 두겠습니다. 나는 데비안 스크레이프를 실행하는 x86_64 프로세서에서 약간 다른 프로그램의 벤치마크를 실행했는데, 그렇지 않으면 대부분 유휴 상태였습니다.
herestring.bash
, herestring을 사용하여 입력 줄을 전달합니다.
#! /bin/bash
i=0
while [ $i -lt $1 ]; do
tr a-z A-Z <<<'hello world'
i=$((i+1))
done >/dev/null
heredoc.bash
, heredoc를 사용하여 입력 행을 전달하십시오.
#! /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
대시에는 이 문자열이 없으므로 제외).
중앙값 트리플은 다음과 같습니다.
$ 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를 버리고 대신 dash 또는 더 나은 ksh를 호출하세요. Bash의 성능은 상대적인 느린 속도를 보완하지 못하지만 ksh는 성능과 속도를 모두 갖추고 있습니다.
성능 외에도 명확성과 이식성이 있습니다. <<<
ksh93/bash/zsh 확장이지만 잘 echo … |
알려져 있지는 않습니다 <<
. ksh88/pdksh 또는 POSIX sh에서는 작동하지 않습니다.
더 명확하다고 할 수 있는 유일한 곳은 <<<
구분 기호 내부입니다.
foo=$(tr a-z A-Z <<<'hello world')
비교됨
foo=$(tr a-z A-Z <<'EOF'
hello world
EOF
)
(대부분의 쉘은 이를 포함하는 줄 끝에 있는 대괄호를 처리할 수 없습니다 <<EOF
.)
답변2
여기에서 문서를 사용하는 또 다른 이유(문서가 충분하지 않은 경우)는 스트림이 소비되지 않으면 에코가 실패할 수 있다는 것입니다. 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
답변3
echo를 사용하려는 한 가지 이유는 heredocs 및 herestrings 끝에 추가된 개행 문자를 어느 정도 제어할 수 있다는 것입니다.
세 문자 foo
의 길이는 3입니다.
$ echo -n foo | wc -c
3
그러나 여기서는 3개의 문자열이 4개의 문자입니다.
$ wc -c <<< foo
4
또한 3자리 구분 기호:
$ wc -c << EOF
foo
EOF
4
네 번째 문자는 개행 문자입니다 0x0a
.
어떻게 든 이것은 bash가 서브 쉘에서 출력을 얻을 때 이러한 줄 바꿈을 제거하는 방식에 마술처럼 맞습니다.
foo
이는 4개의 문자( 및 ) 를 반환하는 명령입니다 \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
그러면 테스트가 통과됩니다.