¿Por qué hay un / bin / echo y por qué querría usarlo?

52

Noté que hay un ejecutable binario /bin/echoen mi sistema Ubuntu MATE 17.04.

Pensé, eso es extraño, porque

$ type echo
echo is a shell builtin

Las pruebas cursivas sugieren que /bin/echohace el mismo tipo de cosas que el Bash incorporado echo:

$ /bin/echo foo
foo
$ /bin/echo $USER
zanna

Entonces, ¿por qué hay otra versión echoseparada del programa Bash y por qué o cuándo querría usarlo?

Zanna
fuente
2
@ bodhi.zazen Eso es bastante útil a pesar de que no es lo mismo, porque aborda lo contrario de esta pregunta. Esa pregunta pregunta por qué echose proporciona como un shell incorporado, mientras que esta pregunta por qué se proporciona como un comando externo.
Eliah Kagan
3
Una razón es que no todos usan bash. Supongo que / bin / echo es anterior a bash, y los desarrolladores consideraron útil / eficiente incluirlo como incorporado en lugar de usar el ejecutable.
jamesqf

Respuestas:

87

Si abre una bashsolicitud y escribe un echocomando, que utiliza un shell incorporado en lugar de ejecutarse /bin/echo. Las razones por las que todavía es importante /bin/echoexistir son:

  1. No siempre estás usando un caparazón. En una variedad de circunstancias, ejecuta un ejecutable directamente y no a través de un shell.
  2. Al menos en teoría, algunos proyectiles no tienen echoincorporado. Esto no es realmente requerido.

Para ampliar el # 1, suponga que desea mover todos los archivos regulares cuyos nombres comenzado con abccualquier parte srca dest. Hay varias formas de hacerlo, pero una de ellas es:

find src -name 'abc*' -type f -exec mv -nv {} dest/ \;

Pero supongamos que, en lugar de solo ejecutar eso, desea ver todos los comandos que se ejecutarán primero. Bueno, entonces puedes anteponer echoel comando, tal como lo harías en otros contextos:

find src -name 'abc*' -type f -exec echo mv -nv {} dest/ \;

Pero findno usa una concha. Eso corre /bin/echo.

Además findde -execo-execdir , el /bin/echoejecutable será llamado por otros programas que ejecutan programas pero no a través de un shell. Esto sucede con el xargscomando (que está relacionado con find), así como en otros contextos, como la Exec=línea de un .desktoparchivo . Otro ejemplo es cuando ejecuta sudo echo, que puede ser útil para probar si sudoestá funcionando.

Del mismo modo, algunas conchas tienen una printfconstrucción pero /usr/bin/printftambién existe.

Una razón posible menos común que podría usar deliberadamente /bin/echoes si confiaba en las diferencias entre este y el echocomando proporcionado por su shell. man echodocumentos /bin/echo; help echoen bash documentos el bashincorporado. echono es muy portátil, porque las diferentes implementaciones, tanto en sistemas operativos como en shells en el mismo sistema operativo, admiten diferentes opciones (por ejemplo, -e) y difieren en el tratamiento de las barras invertidas . Por supuesto, es mejor evitar depender de esos detalles y usarlos printf, que es mucho más portátil .

En bash, puedes hacer que el typeespectáculo incorporado /bin/echotambién, suponiendo que /binesté en tu $PATHcomo siempre debería ser, pasándole la -abandera :

$ type -a echo
echo is a shell builtin
echo is /bin/echo
Eliah Kagan
fuente
21
Y también porque la especificación POSIX dice que tiene que haber uno.
Glenn Jackman
44
@glennjackman ¡Esperaba que alguien publicara una respuesta sobre eso, en realidad, y espero que decidas hacerlo! Sin embargo, hay algo de sutileza, ya que ni Debian, Ubuntu ni GNU Coreutils (ni el Proyecto GNU en general) intentan cumplir con POSIX en todo . Por ejemplo, POSIX insiste en que cdexiste un ejecutable (que, cuando se ejecuta, cambia el directorio y se cierra, dejando al llamador donde estaba antes) y algunos sistemas operativos tienen uno. Puede ser útil citar 4.1 en los estándares GNU .
Eliah Kagan
@EliahKagan: Incidentalmente / usr / bin / cd tiene un uso: / usr / bin / cd El comando de directorio ejecuta ese comando en ese directorio. Si el cambio de directorio falla, el comando no se inicia.
Joshua
44
@Joshua un mejor uso cdes simplemente como una prueba de capacidad para acceder a un directorio dado: si /usr/bin/cd some/dirtiene éxito, de una sola vez ha probado: a) que some/direxiste, b) que es un directorio o un enlace a uno, yc) el existen los permisos necesarios para acceder a ese directorio; todo sin cambiar tu propio estado.
muru
1
@CarlWitthoft, vea ¿Por qué printf es mejor que echo? Además /bin/echo, no \bin\echo, a menos que estés usando Windows. ;)
Comodín el
31

Eliah ha hecho un gran trabajo respondiendo esto, pero quiero comentar sobre la parte de "por qué hay otra versión echoseparada del programa Bash". Esa es la pregunta equivocada.

La pregunta correcta es: ¿por qué es esto una construcción incorporada en primer lugar , cuando podría haber sido (y es) un comando externo perfectamente bien?

Por simplicidad, eche un vistazo a los builtins en el tablero, un mísero 38 (bash tiene 61, en comparación, según la salida de compgen -b):

.               continue        getopts         readonly        type
:               echo            hash            return          ulimit
[               eval            jobs            set             umask
alias           exec            kill            shift           unalias
bg              exit            local           test            unset
break           export          printf          times           wait
cd              false           pwd             trap
command         fg              read            true

¿Cuántos de estos necesitan ser incorporados? [, echo, false, printf, pwd, test, Y trueno necesitan ser órdenes internas: Ellos no hacen nada que sólo una orden interna puede hacer (o afectar obtener estado de cuerpo que no está disponible para comandos externos). Bash, printfal menos, se aprovecha de ser un incorporado: printf -v varguarda la salida en la variable var. timeen bash también es especial: al ser una palabra clave, puede cronometrar listas de comandos arbitrarias en bash (el guión no tiene un timeequivalente). pwdtampoco es necesario que esté integrado: cualquier comando externo heredará el directorio de trabajo actual (y también es un comando externo ).:es una excepción, necesita un NOP y lo :es. El resto realiza acciones que un comando externo puede realizar fácilmente.

Por lo tanto, una quinta parte de estas incorporaciones no necesita ser incorporada. ¿Porqué entonces? La página de dashmanual * en realidad explica de pasada por qué estos son incorporados (énfasis mío):

Builtins
 Esta sección enumera los comandos incorporados que están incorporados porque
 necesita realizar alguna operación que no puede ser realizada por otro
 proceso. Además de estos, hay varios otros comandos que pueden
 estar construido para la eficiencia (por ejemplo, printf (1), echo (1), prueba (1), etc.).

Eso es casi todo: estas construcciones están ahí porque se usan con tanta frecuencia, de forma interactiva y en scripts, y su funcionalidad es lo suficientemente simple como para que el shell pueda hacer el trabajo. Y lo que sucede: algunos (?) La mayoría de las conchas tomaron en el trabajo posterior ** Ir a. Lash de 2.9 BSD , y usted no encontrará una echoorden interna.

Por lo tanto, es completamente posible que un shell mínimo pueda omitir la implementación de comandos como los incorporados (no creo que ningún shell actual lo haga). El proyecto GNU coreutils no asume que los va a ejecutar en un shell particular, y POSIX requiere estos comandos. Entonces, coreutils proporciona estos de todos modos y omite aquellos que no tienen ningún significado fuera del shell.


* Esto es casi idéntico al texto de página de manual correspondiente para el shell Almquist , que es en lo que se basa el guión, el shell Debian Almquist.

** zshlleva esta idea al extremo: los comandos que obtienes al cargar varios módulos, como zmv, son cosas en las que no pensarías que un shell necesita siquiera entrar . En ese punto, la verdadera pregunta es: ¿por qué usarías bash en lugar de zsh, que tiene todas estas funciones integradas?

muru
fuente
1
Resulta que: no necesita ser un constructor tampoco. Es una tontería que no sea una construcción. A menos que esté lidiando con problemas iniciales de nivel de disco de rescate de inicio (en cuyo caso descubrí que pwd tampoco funciona de manera confiable), la única penalidad por no tener esto como un generador incorporado es un rendimiento terrible.
Joshua
55
@Joshua no, :ya que un externo realmente no sería un NOP, todavía tendría que PATHbuscar, intentar ejecutar el comando, etc., cuando todo lo que realmente quiere es no hacer nada expresamente. :como un constructor hace eso.
muru
2
Bash realmente necesita pwdser incorporado para que funcione de la manera que lo hace, con el comportamiento predeterminado de mostrar la ruta "lógica" ( pwd -L). /bin/pwdsolo podría implementar el pwd -Pcomportamiento de mostrarle los directorios principales reales, no el enlace simbólico que editó cd.
Peter Cordes
2
pwdEl estado de @PeterCordes está un poco comprometido por la presencia de PWD, pero sí, eso también es una instancia de bash que usa el estado incorporado para mejorar la funcionalidad
muru