Comprender los comandos integrados de shell

12

En el manual de bash , está escrito que

Builtin commands are contained >>> within <<< the shell itself

Además, esta respuesta dice que

A built-in command is simply a command that the shell carries out itself,
instead of interpreting it as a request to load and run some
>>> other program <<<

Cuando corro compgen -ben bash 4.4, recibo una lista de todos los comandos shell incorporado. Veo, por ejemplo, eso [y killse enumeran para ser construcciones de shell. Pero sus ubicaciones reales son:

/usr/bin/[
/bin/kill

Pensé que ser un builtinmedio significa que el comando se compila en el /bin/bashejecutable. Entonces, ¿qué es lo que realmente me confunde? Corríjame, pero ¿cómo puede ser un comando separado builtin, cuando en realidad no es parte del shell?

manifestante
fuente
1
Algunos comandos existieron originalmente como utilidades separadas. Su presencia ahora es para el cumplimiento del estándar POSIX, la portabilidad y la compatibilidad con versiones anteriores. Los shells implementan algunos como integrados para el rendimiento Puede haber otra razón, pero eso es todo sin demasiados detalles.
Sergiy Kolodyazhnyy
1
Otra razón por la que podría pensar, es porque se necesitan algunos comandos integrados para shell específicamente, como execmanipular descriptores de archivos y eval evaluar los comandos. No son necesarios como comandos independientes
Sergiy Kolodyazhnyy

Respuestas:

16

Los comandos que están integrados en el shell a menudo están integrados debido al aumento de rendimiento que esto proporciona. Llamar al externo printf , por ejemplo, es más lento que usar el incorporado printf.

Dado que algunas utilidades no necesitan ser incorporadas, a menos que sean especiales, como cd, también se proporcionan como utilidades externas . Esto es para que los scripts no se rompan si son interpretados por un shell que no proporciona un equivalente incorporado.

Algunos complementos de shell también proporcionan extensiones al comando externo equivalente. Bash printf, por ejemplo, es capaz de hacer

$ printf -v message 'Hello %s' "world"
$ echo "$message"
Hello world

(imprimir en una variable) que el externo /usr/bin/printfsimplemente no podría hacer ya que no tiene acceso a las variables de shell en la sesión de shell actual (y no puede cambiarlas).

Las utilidades integradas tampoco tienen la restricción de que su línea de comando expandida tenga que ser más corta que cierta longitud. Haciendo

printf '%s\n' *

por lo tanto, es seguro si printfes un comando incorporado de shell. La restricción en la longitud de la línea de comando proviene de la execve()función de biblioteca C utilizada para ejecutar un comando externo. Si la línea de comando y el entorno actual es mayor que ARG_MAXbytes (ver getconf ARG_MAXen el shell), la llamada a execve()fallará. Si la utilidad está integrada en el shell, execve()no es necesario llamarla.

Las utilidades integradas tienen prioridad sobre las utilidades que se encuentran en $PATH. Para deshabilitar un comando incorporado bash, use eg

enable -n printf

Hay una breve lista de utilidades que deben integrarse en un shell (tomado de la lista de incorporaciones especiales del estándar POSIX )

break
colon (:)
continue
dot (.)
eval
exec
exit
export
readonly
return
set
shift
times
trap
unset

Es necesario incorporarlos, ya que manipulan directamente el entorno y el flujo del programa de la sesión de shell actual. Una utilidad externa no podría hacer eso.

Curiosamente, cdno forma parte de esta lista, pero POSIX dice lo siguiente al respecto:

Dado que cdafecta el entorno actual de ejecución del shell, siempre se proporciona como un shell integrado normal. Si se llama en un subshell o en un entorno de ejecución de utilidad separado, como uno de los siguientes:

(cd /tmp)
nohup cd
find . -exec cd {} \;

no afecta el directorio de trabajo del entorno de la persona que llama.

Por lo tanto, supongo que las incorporaciones "especiales" no pueden tener contrapartes externas, mientras que cden teoría podría tener (pero no haría mucho).

Kusalananda
fuente
IIRC, chdir/ cderan binarios externos en los primeros Unices / pre-Unix antes de que forkse introdujera.
Xophmeister
@Xophmeister Solaris 11.4 (beta) todavía tiene /usr/bin/cd, pero en realidad no cambiará el directorio de trabajo actual. Su manual dice: /usr/bin/cdno tiene ningún efecto en el proceso de invocación, pero se puede usar para determinar si un directorio dado se puede establecer como el directorio actual.
Kusalananda
2
Otra razón bastante específica para los builtins: el builtin killtambién es bueno porque no necesita bifurcar otro proceso, bueno si has alcanzado el límite de tu número de procesos.
derobert
7

Usted está (muy comprensible) confundido por el hecho de que existen algunas órdenes internas tanto como órdenes internas y como comandos externos. Entonces, si bien tiene razón en que, por ejemplo, hay un /bin/[comando, eso no significa que su "ubicación real" esté dentro /bin.

Cualquier forma fácil de probar esto es ejecutar typecon el -ainterruptor que mostrará todas las instancias disponibles de un comando. En mi sistema Arch, eso muestra:

$ type -a [
[ is a shell builtin
[ is /sbin/[
[ is /usr/sbin/[
[ is /usr/bin/[

Tenga en cuenta que /sbin, /usr/sbiny /bintodos los enlaces simbólicos apuntan /usr/bin, por lo que solo hay un externo [:

$ readlink -f /usr/sbin /sbin /bin/
/usr/bin
/usr/bin
/usr/bin

Como puede ver, [es tanto un comando incorporado como un comando externo, y lo mismo es cierto para varios otros constructores de shell. Sin embargo, eso no cambia el hecho de que también son componentes integrados de shell, compilados en el propio shell.

terdon
fuente
¿Por qué distro? proporcionar un comando externo separado para un comando interno ya existente? ¿Por qué se duplican?
LoveWithMaths
1
@linuxuser POSIX requiere algunas de estas utilidades, y no puede saber si el shell que está utilizando un usuario también proporcionará una función incorporada. No piense en ellos como un comando interno del sistema operativo, son solo comandos internos del shell y el shell puede cambiar.
terdon
Tengo 1 duda ahora, si los comandos internos son proporcionados por shell; entonces, ¿quién proporciona comandos externos? como he observado muchos comandos que están disponibles como comando interno y externo, pero no los instalé explícitamente; Entonces, ¿quién proporciona el comando externo? ¿Distro les proporciona lo correcto?
LoveWithMaths
@linuxuser depende del comando y del sistema operativo. Por ejemplo, en mi Arch Linux, /bin/printfes instalado por el coreutilspaquete y /bin/killpor util-linux.
terdon
Lo siento pero aún no estoy claro, ¿cuál de los anteriores es proporcionado por la distribución? y qué pasa con el otro que no es proporcionado por la distribución y luego quién lo proporciona.
LoveWithMaths