GNU/Linux >> Tutoriales Linux >  >> Linux

¿Qué sucede exactamente cuando ejecuto un archivo en el Shell?

Entonces, pensé que tenía una buena comprensión de esto, pero realicé una prueba (en respuesta a una conversación en la que no estaba de acuerdo con alguien) y descubrí que mi comprensión es defectuosa...

Con el mayor detalle posible ¿Qué sucede exactamente cuando ejecuto un archivo en mi shell? Lo que quiero decir es que si escribo:./somefile some arguments en mi shell y presione regresar (y somefile existe en el cwd, y tengo permisos de lectura y ejecución en somefile ) entonces, ¿qué sucede debajo del capó?

Yo pensé la respuesta fue:

  1. El shell hace una llamada del sistema a exec , pasando la ruta a somefile
  2. El núcleo examina somefile y mira el número mágico del archivo para determinar si es un formato que el procesador puede manejar
  3. Si el número mágico indica que el archivo está en un formato que el procesador puede ejecutar, entonces
    1. se crea un nuevo proceso (con una entrada en la tabla de procesos)
    2. somefile se lee/asigna a la memoria. Se crea una pila y la ejecución salta al punto de entrada del código de somefile , con ARGV inicializado en una matriz de parámetros (un char** , ["some","arguments"] )
  4. Si el número mágico es un shebang entonces exec() genera un nuevo proceso como el anterior, pero el ejecutable utilizado es el intérprete al que hace referencia el shebang (por ejemplo, /bin/bash o /bin/perl ) y somefile se pasa a STDIN
  5. Si el archivo no tiene un número mágico válido, se produce un error como "archivo no válido (número mágico incorrecto):error de formato Exec"

Sin embargo, alguien me dijo que si el archivo es texto sin formato, entonces el shell intenta ejecutar los comandos (como si hubiera escrito bash somefile ). No lo creía, pero lo probé y fue correcto. Así que claramente tengo algunos conceptos erróneos sobre lo que realmente sucede aquí y me gustaría entender la mecánica.

¿Qué sucede exactamente cuando ejecuto un archivo en mi shell? (con tanto detalle es razonable…)

Respuesta aceptada:

La respuesta definitiva a "cómo se ejecutan los programas" en Linux es el par de artículos en LWN.net titulados, sorprendentemente, Cómo se ejecutan los programas y Cómo se ejecutan los programas:binarios ELF. El primer artículo aborda los guiones brevemente. (Estrictamente hablando, la respuesta definitiva está en el código fuente, pero estos artículos son más fáciles de leer y proporcionan enlaces al código fuente).

Un poco de experimentación muestra que prácticamente lo hizo bien, y que la ejecución de un archivo que contiene una lista simple de comandos, sin un tinglado, debe ser manejada por el shell. La página de manual de execve(2) contiene código fuente para un programa de prueba, execve; usaremos eso para ver qué sucede sin un caparazón. Primero, escriba un script de prueba, testscr1 , que contiene

#!/bin/sh

pstree

y otro, testscr2 , que contiene solo

pstree

Haz que ambos sean ejecutables y verifica que ambos se ejecuten desde un shell:

chmod u+x testscr[12]
./testscr1 | less
./testscr2 | less

Ahora inténtalo de nuevo, usando execve (asumiendo que lo construiste en el directorio actual):

./execve ./testscr1
./execve ./testscr2

testscr1 todavía se ejecuta, pero testscr2 produce

execve: Exec format error

Esto muestra que el shell maneja testscr2 diferentemente. Sin embargo, no procesa el script en sí mismo, todavía usa /bin/sh Para hacer eso; esto se puede verificar canalizando testscr2 a less :

./testscr2 | less -ppstree

En mi sistema, obtengo

    |-gnome-terminal--+-4*[zsh]
    |                 |-zsh-+-less
    |                 |     `-sh---pstree

Como puede ver, está el shell que estaba usando, zsh , que empezó less , y un segundo shell, simple sh (dash en mi sistema), para ejecutar el script, que ejecutó pstree . En zsh esto lo maneja zexecve en Src/exec.c :el shell usa execve(2) para intentar ejecutar el comando, y si eso falla, lee el archivo para ver si tiene un shebang, procesándolo en consecuencia (lo que también habrá hecho el núcleo), y si eso falla, intenta ejecutar el archivo con sh , siempre que no haya leído ningún byte cero del archivo:

        for (t0 = 0; t0 != ct; t0++)
            if (!execvebuf[t0])
                break;
        if (t0 == ct) {
            argv[-1] = "sh";
            winch_unblock();
            execve("/bin/sh", argv - 1, newenvp);
        }

bash tiene el mismo comportamiento, implementado en execute_cmd.c con un comentario útil (como lo señaló taliezin):

Ejecute un comando simple que, con suerte, esté definido en un archivo de disco
en algún lugar.

  1. fork ()
  2. conectar tuberías
  3. busque el comando
  4. hacer redirecciones
  5. execve ()
  6. Si execve falló, vea si el archivo tiene configurado el modo ejecutable.
    Si es así, y no es un directorio, entonces ejecute su contenido como
    un script de shell.

POSIX define un conjunto de funciones, conocidas como exec(3) funciones, que envuelven execve(2) y proporcionar esta funcionalidad también; vea la respuesta de muru para más detalles. En Linux, al menos estas funciones son implementadas por la biblioteca C, no por el kernel.

Relacionado:¿el propósito de la palabra clave "do" en Bash para bucles?
Linux
  1. ¿Detectar el sistema Init usando el shell?

  2. ¿Qué sucede cuando ejecuto el comando Cat /proc/cpuinfo?

  3. Linux:¿qué sucede cuando ejecuta Rsync sin una ruta de destino?

  4. ¿Cuál es el propósito del archivo .bashrc en Linux?

  5. no se puede ejecutar un archivo binario cuando se intenta ejecutar un script de shell en Linux

¿Qué es el Shell en Linux?

¿Cómo ejecutar un archivo .sh cuando comienza la sesión?

Qué sucede en segundo plano cuando ejecuta el comando "useradd" en Linux

¿Qué es un archivo .sh?

¿Qué es el sticky bit en los sistemas de archivos UNIX? ¿Cuándo se usa?

¿Cuál es el shell predeterminado de Busybox?