Entiendo que el comando command
está especificado en elúltimo estándar POSIXy builtin
no lo es. También me doy cuenta de que ambos comandos sonincorporaciones regulares(es decir, pueden sobrescribirse mediante funciones definidas por el usuario). Algunos shells definen builtin
, pero no todos (por ejemplo, dash
no). Quiero entender por qué builtin
se introdujo en algunos shells.
Hasta donde tengo entendido, builtin
solo devolverá elementos integrados especiales y luego regulares, pero command
devolverá elementos integrados especiales, luego integrados regulares y luego comandos en la ruta (y -p
se puede usar el modificador command
para especificar su uso). el valor predeterminado definido por el shell $PATH
en caso de que el usuario haya modificado el $PATH
archivo ).
Por ejemplo, en mksh
, veo lo siguiente:
(NOTA: mksh
instalado en Ubuntu 20.04 desde el repositorio http://archive.ubuntu.com/ubuntu focal/universe amd64 mksh amd64 58-1
)
$ echo $KSH_VERSION
@(#)MIRBSD KSH R58 2020/03/27
$ which -a echo
/usr/bin/echo
/bin/echo
$ which -a printf
/usr/bin/printf
/bin/printf
$ type echo
echo is a shell builtin
$ type printf
printf is /usr/bin/printf
$ command echo 'Hello World!'
Hello World!
$ command printf 'Hello World!\n'
Hello World!
$ builtin echo 'Hello World!'
Hello World!
$ builtin printf 'Hello World!\n'
mksh: builtin: printf: not found
$ sudo cp /usr/bin/printf /usr/bin/printf.backup
$ sudo cp /bin/printf /bin/printf.backup
$ sudo rm /usr/bin/printf
$ sudo rm /bin/printf
rm: cannot remove '/bin/printf': No such file or directory
$ sudo cp /usr/bin/printf.backup ~/printf
$ echo $PATH | sed 's/:/\n/g'
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
# ...remainder ommitted here for brevity
$ export PATH=~:$PATH
$ echo $PATH | sed 's/:/\n/g'
/home/my_username
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
# ...remainder ommitted here for brevity
$ command printf 'Hello World!\n'
Hello World!
$ command -p printf 'Hello World!\n'
mksh: printf: inaccessible or not found
¿Es correcto mi entendimiento? ¿O hacer command
y builtin
hacer exactamente lo mismo (y si es así, por qué se builtin
introdujo?). ¿O hay otra diferencia sutil entre command
y builtin
?
(Intenté buscar una respuesta en StackExchange, pero no encontré nada, por lo que si alguien puede indicarme una respuesta adecuada, estaría muy agradecido).
ACTUALIZAR:
También vale la pena señalar que command
" builtin
omita" la búsqueda y el uso de alias definidos. La expansión de alias viene antes de la búsqueda y evaluación de comandos, al igual que la expansión aritmética, de variables y de comodines de archivos, en el orden de evaluación del shell POSIX. Sin embargo, la aritmética, las variables y los comodines se evalúan dentro de command
y builtin
, pero no los alias. Parece algo que los documentos deberían mencionar.
Por ejemplo:
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ command echo $((1 + 1))
2
$ builtin echo $((3 + 1))
4
pero
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ alias \[='echo hello'
$ [
hello
$ if builtin [ 'north' != 'south' ]; then echo 'what a world!'; fi
what a world!
ACTUALIZACIÓN 2:
Creo que también vale la pena señalar que, después de investigar y experimentar un poco, descubrí que zsh
se comportaTODO LO CONTRARIOdel estándar POSIX y otros shells de estilo Bourne con respecto al command
comando.
Desde eldocumentos zsh(Sección 6.2, Modificadores de precomando)
comando [-pvV]
La palabra de comando se considera el nombre de un comando externo, en lugar de una función de shell o incorporada.
Por ejemplo
$ echo ${ZSH_VERSION}
5.8
$ command cd ~
zsh: command not found: cd
$ command -p cd ~
zsh: command not found: cd
$ command echo 'hi'
hi
# `echo` is a regular builtin just like `cd` though...??!!!
$ set -o |grep posix
posixaliases off
posixargzero off
posixbuiltins off
posixcd off
posixidentifiers off
posixjobs off
posixstrings off
posixtraps off
$ cd() { echo 'I told you.'; }
$ cd
I told you.
# ????!!!!
Solo si la POSIX_BUILTINS
variable de entorno está configurada (use set -o posixbuiltins
), el comando command
también ejecutará funciones integradas especiales y regulares.
Por ejemplo
$ echo ${ZSH_VERSION}
5.8
$ cd /
$ ls
bin dev home lib lib64 lost+found mnt proc run snap sys usr
boot etc init lib32 libx32 media opt root sbin srv tmp var
$ set -o posixbuiltins
$ command cd ~
$ ls
Desktop Downloads Pictures Templates
Documents Music Public Videos
$ command -p cd /
$ ls
bin dev home lib lib64 lost+found mnt proc run snap sys usr
boot etc init lib32 libx32 media opt root sbin srv tmp var
Por otro lado, desde eldocumentos bash
dominio
comando [-pVv]comando [argumentos…]Ejecuta un comando con argumentos ignorando cualquier función del shell denominada comando. Sólo se ejecutan los comandos integrados del shell o los comandos encontrados al buscar en la RUTA.
Por ejemplo
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ cd /
$ ls
bin dev home lib lib64 lost+found mnt proc run snap sys usr
boot etc init lib32 libx32 media opt root sbin srv tmp var
$ set +o posix # Turn off POSIX mode
$ command cd ~
$ ls
Desktop Downloads Pictures Templates
Documents Music Public Videos
$ command -p cd /
$ ls
bin dev home lib lib64 lost+found mnt proc run snap sys usr
boot etc init lib32 libx32 media opt root sbin srv tmp var
Así zsh
se comportaTODO LO CONTRARIOde otros shells estilo Bourne con respecto al command
comando... Estoy empezando a disgustarme zsh
cada vez más... cuidado con el comprador (advertencia emptor) Supongo.
ACTUALIZACIÓN 3:
También vale la pena señalar que ksh88
no tiene un command
comando incorporado. Esto fue introducido en ksh93
. Para reemplazar un archivo integrado ksh88
, tendría que usar una extraña combinación de alias, funciones y comillas.
(Fuente: Robbins, Arnold; Rosenblatt, Bill. Aprendizaje de Korn Shell: programación en Unix (p. 456). Medios O'Reilly. Versión Kindle.)
Esto es consistente con la respuesta de @Gilles 'SO- deja de ser malvado'.
Respuesta1
ElJustificación POSIX paracommand
responde a la mayoría de los aspectos históricos de su pregunta.
EldominioLa utilidad es algo similar al shell de la octava edición.incorporadocomando, pero desdedominiotambién va al sistema de archivos para buscar utilidades, el nombreincorporadoNo sería intuitivo.
(…) Eldominio -vy-VSe agregaron opciones para satisfacer los requisitos de los usuarios que actualmente cumplen tres utilidades históricas diferentes:tipoen el shell del Sistema V,De dóndeen KornShell, ycualen el caparazón C.
En elOctava edición sh, el builtin
incorporado fue documentado como simplemente omitiendo funciones:
Ejecute el comando especial integrado (como break) independientemente de las funciones definidas con el mismo nombre.
Los alias aún no existían (y cuando aparecieron, existían diferentes mecanismos para evitarlos). Si desea omitir una función para ejecutar un comando externo, puede proporcionar su ruta completa, lo que tiene la ventaja de especificar exactamente lo que desea ejecutar en caso de que haya varios ejecutables con ese nombre en la ruta de búsqueda de comandos. La portabilidad entre sistemas donde la ruta completa a un comando podría ser diferente no era una preocupación generalizada. También lo builtin
hizo la única cosa que realmente no se podía hacer de otra manera.
Más tarde, llegó POSIX y agregó una forma estándar de omitir una función. En este contexto, la portabilidad a sistemas donde los comandos externos estaban en diferentes ubicaciones era una gran preocupación, por lo que builtin
no era suficiente, de ahí la novedad command
que omite funciones (y alias, ya que command foo
coloca foo
en una posición donde los alias no se expanden) y encuentra estándares comandos. (Además, hoy en día, ksh tiene un comando integrado llamado builtin
que hace algo completamente diferente, pero no sé si apareció antes o después de la creación de POSIX command
). Sin embargo, command
intencionalmente no omite los comandos integrados, nuevamente debido a problemas de portabilidad: si un sh Un programa invoca un comando estándar, es decisión del sistema operativo si este comando se puede proporcionar de forma integrada. command
cancela el comportamiento de “incorporación especial” de las funciones integradas especiales, nuevamente para que la aplicación no necesite saber si está invocando una función incorporada o no.
No sé por qué zsh command
omite las funciones integradas cuando no está en modo POSIX (específicamente, cuando elposix_builtins
opciónno está configurado). Su implementación actual command
se remonta a un cambio en mayo de 1996 publicado enzsh 2.6 beta 20("eliminar -, exec, noglob y comando de la lista de palabras reservadas"). Dado que esa implementación ya tenía un manejo diferente para el modo POSIX, supongo que era por compatibilidad con una versión anterior de zsh, pero no he investigado más. Puede ser deliberado porque si posix_builtins
no está configurado, las funciones integradas no son necesariamente compatibles con POSIX y, por lo tanto, es mejor no invocarlas si una aplicación usa el command
comando específicamente POSIX.