Echo:

Echo:

printf그것보다 낫다고 들었는데 echo. 내 경험으로는 RHEL 5.8의 프로그램에 일부 텍스트를 입력할 수 없어서 printf사용해야 했던 사례가 하나만 기억납니다 . 하지만 분명히 다른 차이점도 있습니다. 차이점이 무엇인지, 특정 상황에 따라 다른 차이점이 사용되는지 묻고 싶습니다.echoprintf

답변1

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

처음에는 echo어떤 옵션도 허용되지 않았고 아무것도 확장되지 않았습니다. 이것이 하는 일은 공백 문자로 구분되고 개행 문자로 끝나는 출력 인수뿐입니다.

echo "\n\t"이제 어떤 사람들은 줄 바꿈이나 탭을 출력하거나 선택적으로 후행 줄 바꿈을 출력하지 않는 등의 작업을 수행할 수 있다면 좋을 것이라고 생각했습니다.

그런 다음 그들은 더 열심히 생각했지만 해당 기능을 셸에 추가하는 대신( 실제로 탭을 의미하는 perl큰따옴표 안의 배치 와 같이) .\techo

David Korn은 이 오류를 깨닫고 새로운 형태의 쉘 인용을 도입했습니다. 나중에 and에 의해 복사 $'...'되었지만 그때는 너무 늦었습니다.bashzsh

이제 표준 UNIX는 두 문자 의 합이 포함된 인수를 echo수신 하면 이를 출력하지 않고 대신 탭 문자를 출력합니다. 인수를 확인하면 출력이 중지됩니다(따라서 후행 줄 바꿈도 출력되지 않습니다).\t\c

-e다른 쉘/Unix 공급업체/버전에서는 다른 접근 방식을 선택했습니다. 즉, 이스케이프 시퀀스를 확장하는 옵션과 -n후행 줄 바꿈을 출력하지 않는 옵션 을 추가했습니다 . 일부는 -E이스케이프 시퀀스를 비활성화하는 기능을 가지고 있고 일부는 그렇지 않지만 일부는 -n그렇지 않으며 -e한 구현에서 지원하는 이스케이프 시퀀스 목록이 echo다른 구현에서 지원하는 것과 반드시 ​​동일하지는 않습니다.

스벤 마체크(Sven Maschek)는문제의 정도를 보여주는 훌륭한 페이지.

옵션을 지원하는 구현 에서는 일반적으로 옵션의 끝을 표시 echo하는 a에 대한 지원이 없습니다 ( Bourne과 유사하지 않은 일부 쉘 및 장난감 상자 ( Android용 독립 실행형 유틸리티 )에는 이를 수행하는 기능이 내장되어 있지만 zsh는 지원합니다. this), 예를 들어 많은 쉘 에서는 출력하기가 어렵습니다.--echoechoecho-"-n"echo

bash1, ksh93² 또는 yash( 변수) 와 같은 일부 셸에서 $ECHO_STYLE동작은 셸이 컴파일된 방법이나 환경에 따라 달라집니다(환경에서 버전 4를 사용하는 경우 GNU echo의 동작도 변경되며 일부는 pdksh 옵션에 따라 또는 호출 여부). 따라서 동일한 버전의 두 s가 동일하게 동작한다고 보장할 수는 없습니다.$POSIXLY_CORRECTzshbsd_echoposixshbash echobash

POSIX는 다음과 같이 말합니다.첫 번째 인수가 백슬래시를 포함하는 경우 -n동작은 지정되지 않습니다.. bash예를 들어 출력이 POSIX 요구 사항을 따르지 echo -e않기 때문에 echo는 POSIX가 아닙니다. -e<newline>UNIX 사양은 더 엄격하여 출력을 중지하는 이스케이프 시퀀스를 -n포함하여 일부 이스케이프 시퀀스의 확장을 금지하고 요구합니다 .\c

많은 구현이 규정을 준수하지 않는다는 점을 고려하면 이러한 사양은 실제로 문제를 해결하지 못합니다. 심지어 일부도 있습니다인증됨macOS 5 와 같은 시스템은 호환되지 않습니다.

현재의 현실을 정확하게 반영하기 위해,POSIX는 실제로 이렇게 말해야 합니다.:첫 번째 인수가 ^-([eEn]*|-|-help|-version)$확장 정규식과 일치하거나 인수에 백슬래시(또는 αBIG5 문자 세트를 사용하는 로케일과 같이 백슬래시 문자 인코딩을 포함하는 문자 인코딩)가 포함된 경우 동작은 지정되지 않습니다.

전체적으로 백슬래시 문자가 포함되어 있지 않고 로 시작하지 않는지 echo "$var"확인하지 않으면 무엇이 출력될지 알 수 없습니다 . POSIX 사양은 실제로 이 경우 반대 접근 방식을 사용해야 한다고 알려줍니다.$var-printf

이는 제어되지 않은 데이터를 표시하는 데 사용할 수 없음을 의미합니다 echo. 즉, 스크립트를 작성 중이고 외부 입력(사용자로부터 매개변수로 또는 파일 시스템의 파일 이름...)을 받는 경우 echo를 사용하여 표시할 수 없습니다.

좋아요:

echo >&2 Invalid file.

이것은 아니다:

echo >&2 "Invalid file: $file"

(그러나 옵션이 어떤 방식으로든 활성화되지 않은 경우 (컴파일 타임이나 환경을 통해) echo와 같이 일부(UNIX 호환이 아닌) 구현 에서는 제대로 작동할 수 있습니다 .bashxpg_echo

file=$(echo "$var" | tr ' ' _)대부분의 구현에서는 좋지 않습니다(예외는 yashwith ECHO_STYLE=raw( yash'의 변수는 임의의 바이트 시퀀스를 보유할 수 없으므로 임의의 파일 이름을 보유할 수 없음) 및 zsh's 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
     if [ "$#" -gt 0 ]; then
       printf ' %s' "$@"
     fi
  fi
  printf '\n'
}

ksh88, pdksh 및 일부 파생물에는 printf내장되어 있지 않습니다. 거기에서 print -r --(for echo) 및 print -rn --(for echo -n/ \c)를 사용하여 인수를 공백으로 구분하여(뒤에 개행 문자가 옴) 변경 없이 인쇄하는 것을 선호할 수 있습니다 -n( 에서도 작동함 zsh).


노트

bash1. 행동을 바꾸는 방법 echo.

런타임 시 동작을 제어할 수 있는 두 가지(함수 또는 별칭으로 재정의하거나 추가로)가 있습니다 bash. 바로 옵션과 posix 모드인지 여부입니다. 환경에서 호출되거나 다음 옵션을 사용하면 모드를 활성화할 수 있습니다.echoenable -n echoechoxpg_echo bashbashposixbashshPOSIXLY_CORRECTposix

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

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

xpg_echoUNIX에서 요구하는 대로 시퀀스를 확장합니다.

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

여전히 -n다음 -e을 존중합니다 -E.

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

POSIX 모드 사용 xpg_echo:

$ 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

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

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

$

--enable-xpg-echo-defaultxpg_echo 및 posix의 기본값은 스크립트 및 --enable-strict-posix-default옵션을 사용하여 컴파일 타임에 정의할 수 있습니다 configure. 이는 일반적 으로 최신 버전의 OS/ X /bin/sh . 실제로는 그렇지 않습니다. Solaris 11(선택적 패키지)과 함께 제공된 Oracle은 Solaris 10으로 구축된 것으로 보입니다 (Solaris 10에서는 그렇지 않습니다)./bin/bash/bin/bash--enable-xpg-echo-default

2. 행동을 ksh93바꾸는 방법echo

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

$PATH포함된 구성 요소에 이전 /5bin또는 구성 요소 가 포함된 경우 동작은 SysV/UNIX 모드(확장 시퀀스, 허용되는 옵션 없음)입니다. 또는 을 먼저 찾거나 7이 포함되어 있으면 BSD 3 모드 에서 실행됩니다 ( 확장 인식을 활성화하기 위해 )./xpg/bin/usr/bin/ucb/bsd$_AST_FEATURESUNIVERSE = ucb-e-n

builtin getconf; getconf UNIVERSE기본값은 시스템, Debian의 BSD에 따라 다릅니다(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?

여기서 이 옵션을 처리하기 위한 BSD에 대한 참조는 -e약간 오해의 소지가 있습니다. 이러한 다양하고 호환되지 않는 동작의 대부분은 echoAT&T에 의해 도입되었습니다.

  • \n, \0ooo, \cProgrammer's Workbench UNIX(Unix V6 기반), 나머지( \b, \r...)는 Unix System III참조번호.
  • -nUnix V7(데니스 리치)참조번호)
  • -eUnix V8(데니스 리치)참조번호)
  • -Ebash그 자체는 원래 (CWRU/CWRU.chlog) 에서 왔을 수도 있습니다.버전 1.13.5Brian Fox가 1992년 10월 18일에 추가했고 GNU는 echo10일 후에 출시된 sh-utils-1.8에 바로 복사했다고 언급했습니다.

BSD echo의 내장 기능은 90년대 초반 Almquist 쉘을 지원해 왔지만 sh, 현재까지 독립 실행형 유틸리티는 이를 지원하지 않았습니다(-eechoFreeBSDechoUnix V7처럼 지원하지만 여전히 지원되지 않습니다 -e(마지막 인수의 끝에서만).-n\c

BSD에서는 쌍 처리가 s -e에 추가되었습니다 .ksh93echo우주ksh93r의 2006 릴리스에서는 컴파일 타임에 이를 비활성화할 수 있습니다.

4. GNU echo 8.31의 동작 변경

coreutils 8.31부터 시작(및이번에 제출하세요), echo이제 GNU는 POSIXLY_CORRECT가 환경에 존재할 때 내장 함수의 동작과 일치하도록 기본적으로 이스케이프 시퀀스를 확장 합니다 bash -o posix -O xpg_echo(echo오류 보고서).

5. 애플 시스템echo

대부분의 macOS 버전에서 사용 가능OpenGroup으로부터 UNIX 인증 획득.

내장 sh프로그램 (매우 오래된 버전) 은 기본적으로 활성화되어 있기 echo때문에 호환되지만 독립 실행형 유틸리티는 그렇지 않습니다. 아무것도 출력하지 않고 대신 출력 합니다 .bashxpg_echoechoenv echo -n-n<newline>env echo '\n'\n<newline><newline><newline>

이는 첫 번째 인수 가 or 이고(1995년 이후) 마지막 인수가 or 로 끝나는 경우 /bin/echo개행 출력을 억제하는 FreeBSD의 기능이지만 UNIX에서 요구하는 다른 백슬래시 시퀀스는 지원하지 않으며 .-n\c\\

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

/bin/echo엄밀히 말하면 위의 FreeBSD/macOS 도 포함할 수 있습니다 ( echo내장 셸 아님). 여기서 zshs echo -E - "$var"또는 yashs ECHO_STYLE=raw echo "$var"( printf '%s\n' "$var")는 다음과 같이 작성할 수 있습니다.

/bin/echo "$var
\c"

그리고 zsh( echo -nE - "$var")는 printf %s "$var"다음과 같이 쓸 수 있다.

/bin/echo "$var\c"

지원 -E하거나 구성할 수 -n있는 구현은 다음을 수행할 수도 있습니다.

echo -nE "$var
"

동등한 printf '%s\n' "$var".

7. _AST_FEATURES및 ASTUNIVERSE

_AST_FEATURES직접 조작할 수는 없으며 명령 실행 중에 AST 구성 설정을 전파하는 데 사용됩니다 . 구성은 (문서화되지 않은) API를 통해 수행됩니다 astgetconf(). 내부적으로 ksh93내장 getconf함수( builtin getconf호출하거나 활성화하여 command /opt/ast/bin/getconf)는 인터페이스입니다.astgetconf()

예를 들어 설정을 ( SysV 모드에서 실행 되도록 ) 로 builtin getconf; getconf UNIVERSE = att변경 해야 합니다 . 이렇게 하면 환경 변수에 .UNIVERSEattecho$_AST_FEATURESUNIVERSE = att

답변2

printf서식 옵션을 사용할 수도 있습니다 . echo변수나 (간단한) 행의 값을 인쇄할 때 유용하지만 그 이상은 아닙니다. printf기본적으로 C 버전에서 할 수 있는 일을 할 수 있습니다.

사용법 및 기능 예:

Echo:

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

printf:

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

원천:

답변3

그렇게 부르고 싶다면 한 가지 "장점"은 echo특정 이스케이프 시퀀스를 해석하라고 지시할 필요가 없다는 것입니다. 예를 들어 \n해석할 줄 알고 -e.

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

(참고: 마지막 항목은 \n필수이며 옵션을 echo제공하지 않는 한 암시됩니다 )-n

비교적

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

\n마지막 내용을 참고하시기 바랍니다 printf. 결국은 취향의 문제죠필요하다당신은 무엇을 사용합니까:echo또는printf.

답변4

단점 중 하나는 printf내장 셸이 echo훨씬 빠르기 때문에 성능입니다. 이는 새 명령의 각 인스턴스가 상당한 Windows 오버헤드를 발생시키는 Cygwin에서 특히 중요합니다. 무거운 에코를 사용하는 프로그램을 /bin/echo쉘의 에코로 바꾸자 성능이 거의 두 배로 늘어났습니다. 이는 이식성과 성능 간의 균형입니다. 항상 사용하도록 설정하지 않고 잊어버립니다 printf.

관련 정보