에코보다 printf가 더 좋은 이유는 무엇입니까? 하나만 기억할 수

나는 그것 printf보다 낫다고 들었습니다 echo. RHEL 5.8의 일부 프로그램에 텍스트를 공급하는 데는 효과 가 없었지만 사용 printf했기 때문에 사용해야했던 경험에서 인스턴스를 하나만 기억할 수 있습니다 . 그러나 분명히 다른 차이점이 있으며, 하나를 사용할 때와 다른 것을 사용할 때 특정 사례가 있는지뿐만 아니라 그 차이점을 묻고 싶습니다.echoprintf



답변

기본적으로 이식성 (및 안정성) 문제입니다.

처음에는 echo옵션을 수락하지 않았으며 아무것도 확장하지 않았습니다. 공백 문자로 구분되고 개행 문자로 종료되는 인수를 출력하는 것이 전부였습니다.

이제 누군가 줄 echo "\n\t"바꿈 또는 탭 문자를 출력하거나 후행 줄 바꿈 문자를 출력하지 않는 옵션을 사용할 수 있다면 좋을 것이라고 생각했습니다 .

그런 다음 더 열심히 생각했지만 셸에 해당 기능을 추가하는 대신 ( perl큰 따옴표 안에 \t실제로 탭 문자가있는 것처럼)을 추가했습니다 echo.

데이빗 콘은 실수를 깨닫고 쉘 따옴표 새로운 형태의 도입 : $'...'나중에에 의해 복사 된 bash과를 zsh하지만 너무 늦은 시간에 의해했다.

표준 UNIX 지금 때 echo두 개의 문자가 포함 된 인수 수신 \하고 t대신 그들을 출력을, 그것은 탭 문자를 출력합니다. 그리고 \c인수에서 보자 마자 출력을 중지합니다 (따라서 후행 줄 바꿈도 출력되지 않습니다).

다른 쉘 / 유닉스 벤더 / 버전에서는 다르게 선택했습니다 : -e이스케이프 시퀀스를 확장하는 -n옵션 과 후행 줄 바꿈을 출력하지 않는 옵션을 추가했습니다 . 일부는 가지고 -E일부가, 이스케이프 시퀀스를 비활성화 할 -n수 있지만 -e, 하나에 의해 지원되는 이스케이프 시퀀스 목록 echo구현은 다른 지원으로 반드시 동일하지 않습니다.

Sven Mascheck에는 문제의 범위를 보여주는 멋진 페이지가 있습니다 .

이들에 echo옵션을 지원 구현하는 어떠한 지원 일반적으로 없다 --종료 옵션을 표시하는합니다 ( echo할 일부 비 본쉘의 내장, 그리고 zsh을 지원 -하는 생각에 대한) 예를 들어, 그래서 그것을 출력 어려운, "-n"echo에 많은 껍질.

같은 몇 가지 껍질에 bash¹ 또는 ksh93² 또는 yash( $ECHO_STYLE변수), 동작도 GNU 방법 쉘이 컴파일 또는 환경 (에 따라 echo‘경우의 동작도 변경됩니다 $POSIXLY_CORRECT환경과 버전 함께 4 , zsh의 그것과 bsd_echo옵션, 일부 pdksh 기반 posix옵션 또는 호출 여부 sh). 따라서 bash echo동일한 버전의 두 개가 동일한 bash동작을 보장하지는 않습니다.

POSIX의 말 : 첫 번째 인수 -n이거나 임의의 인수에 백 슬래시가 포함되어 있으면 동작이 지정되지 않은 것 입니다. bash그 점에서 echo는 POSIX echo -e가 아닙니다. 예를 들어 -e<newline>POSIX가 요구 하는 대로 출력되지 않습니다 . UNIX 스펙은 더 엄격 -n하므로 \c출력을 중지하기 위해 이스케이프 시퀀스를 포함하여 일부 이스케이프 시퀀스의 확장을 금지 하고 필요로합니다 .

많은 구현이 호환되지 않는 경우 이러한 사양은 실제로 구출되지 않습니다. macOS 5 와 같은 일부 인증 된 시스템도 호환되지 않습니다.

현재 현실을 실제로 나타내려면 POSIX는 실제로 다음과 같이 말해야합니다 . 첫 번째 인수가 ^-([eEn]*|-help|-version)$확장 정규 표현식 과 일치 하거나 인수에 백 슬래시 (또는 αBIG5 문자 세트를 사용하는 로케일 과 같은 백 슬래시 문자 인코딩이 포함 된 문자)가 포함 된 경우 동작은 다음과 같습니다. 불특정.

대체로 백 슬래시 문자를 포함하지 않고로 시작하지 echo "$var"않는지 확인하지 않으면 어떤 결과 가 출력되는지 알 $var수 없습니다 -. POSIX 사양은 실제로 printf그 경우 대신 사용하도록 지시합니다 .

따라서 echo제어 할 수없는 데이터를 표시 하는 데 사용할 수 없습니다 . 즉, 스크립트를 작성 중이고 외부 입력 (사용자의 인수 또는 파일 시스템의 파일 이름 등)을 사용 echo하는 경우 이를 표시하는 데 사용할 수 없습니다 .

괜찮습니다 :

echo >&2 Invalid file.

이것은 아니다:

echo >&2 "Invalid file: $file"

( 컴파일 타임이나 환경을 통해 옵션이 활성화되지 않은 경우 echo와 같은 일부 (UNIX 호환이 아닌) 구현 에서는 정상적으로 작동하지만).bashxpg_echo

file=$(echo "$var" | tr ' ' _)대부분의 구현에서 확인되지 않은 경우 (예외적 인 yashECHO_STYLE=raw(주의 할 점으로 yash의 변수가 임의의 바이트 시퀀스 그렇게하지 임의의 파일 이름)를 길게 할 수 zshS ‘ echo -E - "$var"6 ).

printf반면,의 기본 사용법으로 제한되는 경우 더 안정적입니다 echo.

printf '%s\n' "$var"

$var포함 할 수있는 문자에 상관없이 개행 문자 뒤에 내용을 출력 합니다.

printf '%s' "$var"

후행 줄 바꿈 문자없이 출력합니다.

이제는 printf구현 간에 차이가 있습니다. POSIX에서 지정한 핵심 기능이 있지만 확장 기능이 많이 있습니다. 예를 들어, 일부 %q는 인수를 인용하기 위해 a 를 지원 하지만 어떻게 수행되는지는 쉘마다 다르며 일부 \uxxxx는 유니 코드 문자를 지원 합니다. 동작 printf '%10s\n' "$var"은 멀티 바이트 로케일에 따라 다르며 최소한 세 가지 다른 결과가 있습니다.printf %b '\123'

그러나 결국 POSIX 기능 세트를 고수 printf하고 너무 멋진 것을 시도하지 않으면 문제가 없습니다.

그러나 첫 번째 인수는 형식이므로 변수 / 제어되지 않은 데이터를 포함해서는 안됩니다.

다음을 echo사용하여 보다 안정적인 것을 구현할 수 있습니다 printf.

echo() ( # subshell for local scope for $IFS
  IFS=" " # needed for "$*"
  printf '%s\n' "$*"
)

echo_n() (
  IFS=" "
  printf %s "$*"
)

echo_e() (
  IFS=" "
  printf '%b\n' "$*"
)

local IFS많은 쉘을 사용하거나 다음과 같이 작성하면 서브 쉘 (대부분의 쉘 구현에서 추가 프로세스를 생성 함을 의미 함)을 피할 수 있습니다 .

echo() {
  if [ "$#" -gt 0 ]; then
     printf %s "$1"
     shift
  fi
  if [ "$#" -gt 0 ]; then
     printf ' %s' "$@"
  fi
  printf '\n'
}

노트

1. 방법 bashecho변경 될 수 있습니다 행동.

으로 bash, 실행시의 동작을 제어하는 두 가지가 있습니다 echo(옆 enable -n echo또는 재정의 echo기능 또는 별칭으로)를 다음 xpg_echo bash옵션을 여부는 bashPOSIX 모드에 있습니다. posix모드 bash가로 호출 sh되거나 POSIXLY_CORRECT환경에 있거나 posix옵션을 사용하는 경우 활성화 할 수 있습니다 .

대부분의 시스템에서 기본 동작 :

$ bash -c 'echo -n "\0101"'
\0101% # the % here denotes the absence of newline character

xpg_echo UNIX가 요구하는 순서를 확장합니다 :

$ BASHOPTS=xpg_echo bash -c 'echo "\0101"'
A

여전히 명예 -n-e(그리고 -E) :

$ BASHOPTS=xpg_echo bash -c 'echo -n "\0101"'
A%

xpg_echoPOSIX 모드 :

$ env BASHOPTS=xpg_echo POSIXLY_CORRECT=1 bash -c 'echo -n "\0101"'
-n A
$ env BASHOPTS=xpg_echo sh -c 'echo -n "\0101"' # (where sh is a symlink to bash)
-n A
$ env BASHOPTS=xpg_echo SHELLOPTS=posix bash -c 'echo -n "\0101"'
-n A

이번에 bash는 POSIX와 UNIX를 모두 준수합니다. POSIX 모드에서는 다음 bash과 같이 출력되지 않으므로 여전히 POSIX 호환이 아닙니다 -e.

$ env SHELLOPTS=posix bash -c 'echo -e'

$

xpg_echo 및 posix의 기본값은 컴파일시 --enable-xpg-echo-default--enable-strict-posix-default옵션을 configure스크립트로 사용하여 정의 할 수 있습니다 . 그것은 일반적으로 최신 버전의 OS / X가 빌드하기 위해 수행하는 작업 /bin/sh입니다. 올바른 마음으로 유닉스 / 리눅스 구현 / 배포는 일반적으로 그렇게하지 /bin/bash않습니다 . 사실, 사실은 아닙니다. /bin/bashOracle이 Solaris 11 (선택적 패키지)과 함께 제공 --enable-xpg-echo-default되는 것은 Solaris 10의 경우와 달리 내장 된 것 같습니다 .

2. 방법 ksh93echo동작을 변경할 수 있습니다.

에서 이스케이프 시퀀스를 확장하고 옵션을 인식 ksh93하는지 여부는 환경 변수 및 / 또는 환경 변수 echo의 내용에 따라 다릅니다 .$PATH$_AST_FEATURES

경우는 $PATH포함 된 구성 요소 포함 /5bin또는 /xpg전과 /bin또는 /usr/bin다음은 시스템 V / UNIX의 방식으로 작동 구성 요소 (시퀀스를 확장, 옵션을 적용하지 않습니다). 찾 /ucb거나 /bsd먼저 또는 $_AST_FEATURES7에 포함되어 있으면 UNIVERSE = ucbBSD 3 방식으로 작동합니다 ( -e확장 가능, 인식 -n).

기본값은 시스템에 따라 다릅니다 (데비안의 BSD) ( builtin getconf; getconf UNIVERSE최신 버전 ksh93 의 출력 참조 ).

$ ksh93 -c 'echo -n' # default -> BSD (on Debian)
$ PATH=/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /xpg before /bin or /usr/bin -> XPG
-n
$ PATH=/5binary:$PATH ksh93 -c 'echo -n' # /5bin before /bin or /usr/bin -> XPG
-n
$ PATH=/5binary:$PATH _AST_FEATURES='UNIVERSE = ucb' ksh93 -c 'echo -n' # -> BSD
$ PATH=/ucb:/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /ucb first -> BSD
$ PATH=/bin:/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /bin before /xpg -> default -> BSD

3. echo -e를위한 BSD?

-e옵션 처리를위한 BSD에 대한 언급 은 약간 오해의 소지가 있습니다. 서로 다르고 호환되지 않는 echo행동의 대부분은 AT & T에서 소개되었습니다.

  • \n, \0ooo, \c프로그래머의 워크 벤치 (유닉스 V6 기준) UNIX, 나머지 (에서 \b, \r유닉스 시스템 III에서 …) 참조 .
  • -n유닉스 V7에서 (Dennis Ritchie Ref가 작성 )
  • -e유닉스 V8에서 (Dennis Ritchie Ref가 작성 )
  • -E자체는 아마도 처음 온 bash(에 CWRU / CWRU.chlog 1.13.5 버전 , 브라이언 폭스 1992년 10월 18일에 추가 언급 GNU의 echo십일 이후 출시 된 SH-utils를 1.8에서 조금 후에 복사를)

그동안 echo의 내장 sh또는 BSD의 지원했다 -e가 90 년대 초에 대한 Almquist 쉘을 사용하기 시작한 날 이후, 독립 echo이 날 유틸리티 (거기를 지원하지 않습니다 FreeBSD는echo 아직 지원하지 않습니다 -e는 지원을하지 불구하고, -n같은 유닉스 V7 (그리고 \c마지막 인수의 끝에서만).

의 처리 -e에 추가 ksh93echoBSD의에 때 우주 와 2006 년에 발표 된 ksh93r 버전에서 컴파일시에 해제 할 수 있습니다.

8.31의 GNU 에코 동작 변경

로 coreutils 8.31 (이후 이 커밋 ), GNU는 echo지금 POSIXLY_CORRECT 환경에있을 때의 동작과 일치하도록 기본적으로 이스케이프 시퀀스 확장 bash -o posix -O xpg_echo의의 echo(참조 내장을 버그 리포트를 ).

5. macOS echo

대부분의 macOS 버전은 OpenGroup으로부터 UNIX 인증을 받았습니다 .

그들의 sh내장은 echo그것의로 준수 bash와 내장 (아주 오래된 버전) xpg_echo기본적으로 사용할 수는 있지만, 자신의 독립 실행 형 echo유틸리티가 없습니다. env echo -n대신에 출력하는 것도 -n<newline>, env echo '\n'출력하지 \n<newline>대신 <newline><newline>.

이것은 /bin/echoFreeBSD의 첫 번째 인수 인 경우 첫 번째 인수 인 경우 줄 바꿈 출력을 억제 -n하고 마지막 인수가 끝나는 경우 (1995 년 이후) 줄 바꿈 출력을 억제 \c하지만 UNIX에서 필요로하는 다른 백 슬래시 시퀀스는 지원하지 않습니다 \\.

6. echo임의의 데이터를 그대로 출력 할 수있는 구현

엄밀히 말하면, 당신은 또한 FreeBSD의 / 맥 OS 것을 셀 수 말하기 /bin/echo(안 자신의 쉘 위의 echo내장은) 여기서 zshecho -E - "$var"또는 yash의가 ECHO_STYLE=raw echo "$var"( printf '%s\n' "$var") 작성할 수 있습니다 :

/bin/echo "$var
\c"

지원 구현 -E-n(또는로 구성 할 수 있습니다)도 수행 할 수 있습니다

echo -nE "$var
"

그리고 zsh‘s이 (가) echo -nE - "$var"( printf %s "$var") 기록 될 수있다

/bin/echo "$var\c"

7. _AST_FEATURES그리고 ASTUNIVERSE

_AST_FEATURES직접 조작하는 것은 아닙니다, 명령 실행을 통해 AST 구성 설정을 전파하는 데 사용됩니다. 구성은 문서화되지 않은 astgetconf()API 를 통해 수행되어야합니다 . 내부 ksh93에서 getconf내장 (을 사용 builtin getconf하거나 호출 하여 사용 가능 command /opt/ast/bin/getconf)은astgetconf()

예를 들어 설정을 ( SysV 방식으로 작동 builtin getconf; getconf UNIVERSE = att하도록) 변경해야 UNIVERSE합니다 . 그 후에 환경 변수에 포함되어 있음을 알 수 있습니다 .attecho$_AST_FEATURESUNIVERSE = att


답변

printf형식 옵션 에 사용할 수 있습니다 . echo변수 또는 (간단한) 줄의 값을 인쇄 할 때 유용하지만 그게 전부입니다. printf기본적으로 C 버전의 기능을 수행 할 수 있습니다.

사용법 및 기능 예 :

Echo:

echo "*** Backup shell script ***"
echo
echo "Runtime: $(date) @ $(hostname)"
echo

printf:

vech="bike"
printf "%s\n" "$vech"

출처 :


답변

한 가지 “이점”은 호출하려는 경우와 같은 echo특정 이스케이프 시퀀스를 해석 하는 것처럼 말할 필요가 없다는 것 \n입니다. 그것들을 해석하는 것을 알고 있으며 -e그렇게 할 필요가 없습니다 .

printf "some\nmulti-lined\ntext\n"

(NB : 마지막 옵션 \n이 필요 echo합니다. -n옵션 을 제공하지 않으면 암시합니다 )

echo -e "some\nmulti-lined\ntext"

의 마지막 부분 \n에 유의하십시오 printf. 하루가 끝나면 맛과 요구 사항이 중요합니다. echo또는 printf.


답변

printf내장 쉘 echo이 훨씬 빠르기 때문에 성능의 단점이 있습니다. 이는 특히 새 명령의 각 인스턴스가 Windows 오버 헤드를 많이 발생시키는 Cygwin에서 작동합니다. 에코가 많은 프로그램을 /bin/echo쉘의 에코로 사용하지 않도록 변경 하면 성능이 거의 두 배가되었습니다. 이식성과 성능 사이의 균형입니다. 항상을 사용하는 것은 슬램 덩크가 아닙니다 printf.