He escuchado que printfes mejor que echo. Solo puedo recordar una instancia de mi experiencia en la que tuve que usarla printfporque echono funcionó para alimentar algún texto en algún programa en RHEL 5.8, pero lo printfhizo. Pero al parecer, hay otras diferencias, y me gustaría preguntar cuáles son, así como si hay casos específicos de cuándo usar uno frente al otro.
text-processing
echo
printf
anfibio
fuente
fuente

echo -e?echo -eno funcionash, solo enbash(por alguna razón), y Docker, por ejemplo, usashde forma predeterminada para susRUNcomandosecho -epara mí funciona en Android Terminal, que es esencialmentesh.Respuestas:
Básicamente, es un problema de portabilidad (y confiabilidad).
Inicialmente,
echono aceptó ninguna opción y no expandió nada. Todo lo que estaba haciendo era generar sus argumentos separados por un carácter de espacio y terminados por un carácter de nueva línea.Ahora, alguien pensó que sería bueno si pudiéramos hacer cosas como
echo "\n\t"generar caracteres de nueva línea o tabulación, o tener una opción para no generar el carácter de nueva línea final.Luego pensaron más, pero en lugar de agregar esa funcionalidad al shell (como
perldonde dentro de las comillas dobles, en\trealidad significa un carácter de tabulación), lo agregaronecho.David Korn se dio cuenta del error e introdujo una nueva forma de citas de shell:
$'...'que luego fue copiadabashyzshque ya era demasiado tarde.Ahora, cuando UNIX estándar
echorecibe un argumento que contiene los dos caracteres\yt, en lugar de generarlos, genera un carácter de tabulación. Y tan pronto como ve\cen un argumento, deja de emitirse (por lo que la nueva línea final tampoco se genera).Otros shells / proveedores / versiones de Unix decidieron hacerlo de manera diferente: agregaron una
-eopción para expandir las secuencias de escape y una-nopción para no generar la nueva línea final. Algunos tienen-Eque deshabilitar las secuencias de escape, otros tienen,-npero no-e, la lista de secuencias de escape compatibles con unaechoimplementación no es necesariamente la misma que admite otra.Sven Mascheck tiene una buena página que muestra el alcance del problema .
En esas
echoimplementaciones que soportan opciones, por lo general hay ningún apoyo de un--para marcar el final de las opciones (laechoorden interna de algunas conchas no Bourne-como hacer, y zsh apoya-para que aunque), por lo que, por ejemplo, es difícil salida"-n"conechoen Muchas conchas.En algunos shells como
bash¹ oksh93² oyash($ECHO_STYLEvariable), el comportamiento incluso depende de cómo se compiló el shell o del entorno (echoel comportamiento de GNU también cambiará si$POSIXLY_CORRECTestá en el entorno y con la versión 4 ,zshcon subsd_echoopción, algunos basados en pdksh con suposixopción o si se les llama comosho no). Por lo tanto, dosbashechos, incluso de la misma versión debash, no tienen el mismo comportamiento.POSIX dice: si el primer argumento es
-no cualquier argumento contiene barras invertidas, entonces el comportamiento no está especificado .bashecho en ese sentido no es POSIX porque, por ejemplo,echo -eno se emite-e<newline>como lo requiere POSIX. La especificación UNIX es más estricta, prohíbe-ny requiere la expansión de algunas secuencias de escape, incluida la\cque detiene la salida.Esas especificaciones realmente no vienen al rescate aquí dado que muchas implementaciones no son compatibles. Incluso algunos sistemas certificados como macOS 5 no son compatibles.
Para representar realmente la realidad actual, POSIX debería decir : si el primer argumento coincide con la
^-([eEn]*|-help|-version)$expresión regular extendida o algún argumento contiene barras diagonales inversas (o caracteres cuya codificación contiene la codificación del carácter de barra diagonal inversa comoαen los entornos locales que utilizan el juego de caracteres BIG5), entonces el comportamiento es sin especificarEn general, no sabe qué
echo "$var"generará a menos que pueda asegurarse de que$varno contenga caracteres de barra invertida y no comience con-. La especificación POSIX realmente nos dice que usemosprintfen su lugar en ese caso.Entonces, lo que eso significa es que no se puede usar
echopara mostrar datos no controlados. En otras palabras, si está escribiendo un script y está recibiendo información externa (del usuario como argumentos, o nombres de archivo del sistema de archivos ...), no puede usarechopara mostrarlo.Esto esta bien:
Esto no es:
(Aunque funcionará bien con algunas
echoimplementaciones (no compatibles con UNIX) comobash's cuando laxpg_echoopción no se ha habilitado de una forma u otra, como en el momento de la compilación o en el entorno).file=$(echo "$var" | tr ' ' _)no está bien en la mayoría de las implementaciones (las excepciones sonyashconECHO_STYLE=raw(con la advertencia de queyashlas variables no pueden contener secuencias arbitrarias de bytes, por lo que no son nombres de archivos arbitrarios) yzsh'secho -E - "$var"6 ).printf, por otro lado, es más confiable, al menos cuando se limita al uso básico deecho.Producirá el contenido
$varseguido de un carácter de nueva línea, independientemente de qué carácter pueda contener.Lo generará sin el carácter de nueva línea final.
Ahora, también hay diferencias entre las
printfimplementaciones. POSIX especifica un núcleo de características, pero hay muchas extensiones. Por ejemplo, algunos admiten a%qpara citar los argumentos, pero la forma en que se realiza varía de un shell a otro, algunos admiten\uxxxxcaracteres Unicode. El comportamiento varíaprintf '%10s\n' "$var"en entornos locales de varios bytes, hay al menos tres resultados diferentes paraprintf %b '\123'Pero al final, si te apegas al conjunto de características POSIX
printfy no intentas hacer nada demasiado elegante con él, estás fuera de problemas.Pero recuerde que el primer argumento es el formato, por lo que no debe contener datos variables / no controlados.
Se
echopuede implementar una más confiable usandoprintf, como:El subshell (que implica generar un proceso adicional en la mayoría de las implementaciones de shell) puede evitarse
local IFScon muchos shells, o escribiéndolo así:Notas
1. ¿Cómo
bash'sechocomportamiento puede ser alterado.Con
bash, en tiempo de ejecución, hay dos cosas que controlan el comportamiento deecho(al ladoenable -n echoo redefinirechocomo una función o alias): laxpg_echobashopción y sibashestá en modo posix.posixEl modo se puede habilitar sibashse llama comosho siPOSIXLY_CORRECTestá en el entorno o con laposixopción:Comportamiento predeterminado en la mayoría de los sistemas:
xpg_echoexpande las secuencias como UNIX requiere:Todavía honra
-ny-e(y-E):Con
xpg_echoy modo POSIX:Esta vez,
bashes compatible con POSIX y UNIX. Tenga en cuenta que en el modo POSIX,bashtodavía no es compatible con POSIX ya que no se genera-een:Los valores predeterminados para xpg_echo y posix se pueden definir en el momento de la compilación con las opciones
--enable-xpg-echo-defaulty--enable-strict-posix-defaultpara elconfigurescript. Eso suele ser lo que hacen las versiones recientes de OS / X para construir su/bin/sh.Sin. En realidad, eso no es cierto,/bin/bashembargo, ninguna implementación / distribución de Unix / Linux en su sano juicio lo haría normalmente/bin/bashparece que Oracle con Solaris 11 (en un paquete opcional) está construido--enable-xpg-echo-default(ese no fue el caso en Solaris 10).2. ¿Cómo
ksh93'sechocomportamiento puede ser alterado.En
ksh93, siechose expande secuencias de escape o no y reconoce opciones depende del contenido de las$PATHy / o$_AST_FEATURESvariables de entorno.Si
$PATHcontiene un componente que contiene/5bino/xpgantes del componente/bino/usr/bin, entonces se comporta de la manera SysV / UNIX (expande secuencias, no acepta opciones). Si encuentra/ucbo/bsdprimero o si contiene$_AST_FEATURES7UNIVERSE = ucb, entonces se comporta de la manera BSD 3 (-epara permitir la expansión, reconoce-n).El valor predeterminado depende del sistema, BSD en Debian (consulte la salida de
builtin getconf; getconf UNIVERSElas versiones recientes de ksh93):3. BSD para echo -e?
La referencia a BSD para el manejo de la
-eopción es un poco engañosa aquí. La mayoría de esosechocomportamientos diferentes e incompatibles se introdujeron en AT&T:\n,\0ooo,\cEn el banco de trabajo del programador de UNIX (basado en Unix V6), y el resto (\b,\r...) en UNIX System III Ref .-nen Unix V7 (por Dennis Ritchie Ref )-een Unix V8 (por Dennis Ritchie Ref )-Eposiblemente inicialmente provenía debash(CWRU / CWRU.chlog en la versión 1.13.5 menciona que Brian Fox lo agregó en 1992-10-18, GNU loechocopió poco después en sh-utils-1.8 lanzado 10 días después)Mientras que la
echoorden interna de lossho BSD han apoyado-edesde el día en que comenzaron a utilizar la cáscara Almquist para ello en los años 90, la versión autónoma deechoutilidad para el día de hoy no lo soporta allí ( FreeBSDechotodavía no admite-e, aunque lo hace de soporte-ncomo Unix V7 (y también\cpero solo al final del último argumento)).El manejo de
-ese agregó aksh93'sechocuando está en el universo BSD en la versión ksh93r lanzada en 2006 y puede deshabilitarse en el momento de la compilación.4. GNU echo cambio de comportamiento en 8.31
Desde coreutils 8.31 (y este commit ), GNU
echoahora expande las secuencias de escape por defecto cuando POSIXLY_CORRECT está en el entorno, para que coincida con el comportamiento debash -o posix -O xpg_echo'sechoincorporado (ver informe de error ).5. macOS
echoLa mayoría de las versiones de macOS han recibido la certificación UNIX de OpenGroup .
Su
shconstrucciónechoes compatible, ya que estábash(una versión muy antigua) construida conxpg_echohabilitada por defecto, pero suechoutilidad independiente no lo es.env echo -nno produce nada en lugar de-n<newline>,env echo '\n'produce en\n<newline>lugar de<newline><newline>.Ese
/bin/echoes el de FreeBSD que suprime la salida de nueva línea si el primer argumento es-no (desde 1995) si el último argumento termina en\c, pero no admite ninguna otra secuencia de barra invertida requerida por UNIX, ni siquiera\\.6.
echoimplementaciones que pueden generar datos arbitrarios textualmenteHablando estrictamente, también podría contar que FreeBSD / macOS
/bin/echoarriba (no el de su shellecho) dondezsh'secho -E - "$var"oyash' sECHO_STYLE=raw echo "$var"(printf '%s\n' "$var") podrían escribirse:Las implementaciones que admiten
-Ey-n(o pueden configurarse para) también pueden hacer:Y
zsh'echo -nE - "$var"(printf %s "$var"podría escribirse)7.
_AST_FEATURESy la ASTUNIVERSENo
_AST_FEATURESestá destinado a ser manipulado directamente, se usa para propagar las configuraciones de configuración AST a través de la ejecución de comandos. La configuración debe hacerse a través de laastgetconf()API (no documentada) . Enksh93el interior , elgetconfincorporado (habilitado conbuiltin getconfo invocandocommand /opt/ast/bin/getconf) es la interfaz paraastgetconf()Por ejemplo, harías
builtin getconf; getconf UNIVERSE = attpara cambiar laUNIVERSEconfiguración aatt(haciendoechoque se comporte como SysV entre otras cosas). Después de hacer eso, notará que la$_AST_FEATURESvariable de entorno contieneUNIVERSE = att.fuente
echoexpandir las\xsecuencias en lugar del shell como parte de la sintaxis de las citas es que puede generar un byte NUL (otro diseño incorrectamente discutible de Unix son aquellos delimitados por nulo) cadenas, donde la mitad de las llamadas del sistema (comoexecve()) no pueden tomar secuencias arbitrarias de bytes)printfparece ser un problema ya que la mayoría de las implementaciones lo hacen mal. La única implementación correcta que conozco está enboshy la página de Sven Maschek no enumera los problemas con bytes nulos a través de\0.Es posible que desee utilizar
printfpara sus opciones de formato.echoes útil cuando se trata de imprimir el valor de una variable o una línea (simple), pero eso es todo.printfbásicamente puede hacer lo que la versión C puede hacer.Ejemplo de uso y capacidades:
Echo:printf:Fuentes:
fuente
echopara imprimir una variable puede fallar si el valor de la variable contiene metacaracteres.Una "ventaja", si quiere llamarlo así, sería que no tiene que decirle cómo
echointerpretar ciertas secuencias de escape como\n. Sabe interpretarlos y no requerirá-eque lo haga.(Nota: lo último
\nes necesario, loechoimplica, a menos que des la-nopción)versus
Tenga
\nen cuenta el último enprintf. Al final del día, es cuestión de gustos y requisitos lo que usas:echooprintf.fuente
/usr/bin/echoy elbashincorporado. Eldash,kshy lazshorden internaechono necesita-ecambiar a ampliar caracteres escapados.printf '%s\n' 'foo\bar.Una desventaja
printfes el rendimiento porque el shell incorporadoechoes mucho más rápido. Esto entra en juego particularmente en Cygwin, donde cada instancia de un nuevo comando causa una gran sobrecarga de Windows. Cuando cambié mi programa de eco pesado de usar/bin/echoal eco del shell, el rendimiento casi se duplicó. Es una compensación entre portabilidad y rendimiento. No es una volcada para usar siempreprintf.fuente
printfestá construido en la mayoría de los shells hoy en día (bash, dash, ksh, zsh, yash, algunos derivados de pdksh ... por lo que también incluye los shells que generalmente se encuentran en cygwin). Las únicas excepciones notables son algunospdkshderivados.printfpara generar bytes nulos, pero algunas implementaciones interpretan `\ c 'en la cadena de formato aunque no deberían hacerlo.printfPOSIX no especifica el comportamiento de si lo usa\cen la cadena de formato, por lo que lasprintfimplementaciones pueden hacer lo que quieran a ese respecto. Por ejemplo, algunos lo tratan igual que en el PWBecho(hace que printf salga), ksh lo usa para\cAcaracteres de control (para el argumento de formato printf y para$'...'pero no paraechoniprint!). ¿No está seguro de qué tiene que ver eso con la impresión de bytes NUL, o tal vez se refiere aksh'sprintf '\c@'?