¿Qué hace un comando "exec"?

107

No entiendo el comando bash exec. He visto que se usa dentro de los scripts para redirigir toda la salida a un archivo (como se ve en esto ). Pero no entiendo cómo funciona o qué hace en general. He leído las páginas de manual pero no las entiendo.

llamar
fuente
¿Estás familiarizado con lo que es un proceso ?
fkraiem
1
@fkraiem, ¿qué quieres decir?
becko
Lo siento, quise decir "qué". : p Pero la respuesta parece ser no.
fkraiem
Pero en realidad su script usa execde una manera especial que puede explicarse de manera mucho más simple, escribiré una respuesta.
fkraiem
1
Relacionado: unix.stackexchange.com/q/296838/85039
Sergiy Kolodyazhnyy

Respuestas:

88

man bash dice:

exec [-cl] [-a name] [command [arguments]]
      If command is specified, it replaces the shell.  No new  process
      is  created.  The arguments become the arguments to command.  If
      the -l option is supplied,  the  shell  places  a  dash  at  the
      beginning  of  the  zeroth  argument passed to command.  This is
      what login(1) does.  The -c option causes command to be executed
      with  an empty environment.  If -a is supplied, the shell passes
      name as the zeroth argument to the executed command.  If command
      cannot  be  executed  for  some  reason, a non-interactive shell
      exits, unless the execfail shell option  is  enabled.   In  that
      case,  it returns failure.  An interactive shell returns failure
      if the file cannot be executed.  If command  is  not  specified,
      any  redirections  take  effect  in  the  current shell, and the
      return status is 0.  If there is a redirection error, the return
      status is 1.

Las dos últimas líneas son lo importante: si se ejecuta execsolo, sin un comando, simplemente hará que las redirecciones se apliquen al shell actual. Probablemente sepa que cuando ejecuta command > file, la salida de commandse escribe en filelugar de en su terminal (esto se llama redirección ). Si ejecuta en su exec > filelugar, la redirección se aplica a todo el shell: cualquier salida producida por el shell se escribe en filelugar de a su terminal. Por ejemplo aqui

bash-3.2$ bash
bash-3.2$ exec > file
bash-3.2$ date
bash-3.2$ exit
bash-3.2$ cat file
Thu 18 Sep 2014 23:56:25 CEST

Primero comienzo un nuevo bashshell. Luego, en este nuevo shell ejecuto exec > file, de modo que toda la salida se redirige a file. De hecho, después de eso ejecuto datepero no obtengo salida, porque la salida se redirige a file. Luego salgo de mi shell (para que la redirección ya no se aplique) y veo que de filehecho contiene el resultado del datecomando que ejecuté anteriormente.

fkraiem
fuente
42
Esta es solo una explicación parcial. execsirve para reemplazar también el proceso actual de la shell con un comando, de modo que el padre sigue un camino y el hijo posee pid. Esto no es solo para la redirección. Agregue esta información
Sergiy Kolodyazhnyy
3
Siguiendo el comentario de @ SergiyKolodyazhnyy, el ejemplo que acabo de encontrar que me llevó a esta página es un docker-entrypoint.sh, donde después de realizar varias acciones en la configuración de nginx, la línea final del script es exec nginx <various nginx arguments>. Esto significa que nginx asume el pid del script bash y ahora nginx es el principal proceso de ejecución del contenedor, no el script. Supongo que esto es solo por limpieza, a menos que alguien más sepa una razón más concreta para ello.
Luke Griffiths el
1
@Luke Esto se llama "script de envoltura". Ejemplo de eso también gnome-terminal, que al menos en 14.04 tenía un script de contenedor para configurar argumentos. Y ese es su único propósito, realmente: establecer artes y medio ambiente. Otro caso sería la limpieza: primero
elimine la
Otro execejemplo similar al nginxejemplo dado por @LukeGriffiths es el ~/.vnc/xstartupscript que se vncserverutiliza para configurar un proceso de servidor VNC y luego exec gnome-sessiono exec startkdemás.
Trevor Boyd Smith
@LukeGriffiths, la razón principal de execuna secuencia de comandos de inicio del contenedor es que el PID 1, el ENTRYPOINT del contenedor, tiene un significado especial en Docker. Es un proceso principal que recibe señales, y cuando existe, el contenedor también sale. execsolo una forma de shsalir de esta cadena de comando y hacer que el demonio sea el proceso principal del contenedor.
kkm
45

exec es un comando con dos comportamientos muy distintos, dependiendo de si se usa al menos un argumento o no se usa ningún argumento.

  • Si se pasa al menos un argumento, el primero se toma como un nombre de comando e execintenta ejecutarlo como un comando que pasa los argumentos restantes, si los hay, a ese comando y administra las redirecciones, si las hay.

  • Si el comando pasado como primer argumento no existe, el shell actual, no solo el comando exec, sale por error.

  • Si el comando existe y es ejecutable, reemplaza el shell actual. Eso significa que si execaparece en un script, las instrucciones que siguen a la llamada ejecutiva nunca se ejecutarán (a menos que se execencuentren en una subshell). execnunca regresa Tampoco se activarán trampas de shell como "EXIT".

  • Si no se pasa ningún argumento, execsolo se usa para redefinir los descriptores actuales del archivo shell. El shell continúa después del exec, a diferencia del caso anterior, pero la entrada estándar, la salida, el error o cualquier descriptor de archivo que se haya redirigido surten efecto.

  • Si se usa alguna de las redirecciones /dev/null, cualquier entrada de ella devolverá EOF y cualquier salida se descartará.

  • Puede cerrar los descriptores de archivos utilizando -como origen o destino, por ejemplo exec <&-. Las siguientes lecturas o escrituras fallarán.

Aquí hay dos ejemplos:

echo foo > /tmp/bar
exec < /tmp/bar # exec has no arguments, will only affect current shell descriptors, here stdin
cat # simple command that read stdin and write it to stdout

Este script generará "foo" como el comando cat, en lugar de esperar la entrada del usuario como lo hubiera hecho en el caso habitual tomará su entrada del archivo / tmp / bar que contiene foo.

echo foo > /tmp/bar
exec wc -c < /tmp/bar # exec has two arguments, the control flow will switch to the wc command
cat

Este script se mostrará 4(el número de bytes en / tmp / bar) y finalizará inmediatamente. El catcomando no se ejecutará.

jlliagre
fuente
44
`Algunas publicaciones antiguas nunca envejecen realmente ... +1.
Cbhihe
3
Si alguna de las redirecciones usa / dev / null, el descriptor de archivo asociado se cierra. No, realmente redirige a / desde /dev/null, por lo que las escrituras siguen teniendo éxito y las lecturas devuelven EOF. close(2)en un fd provocaría que las llamadas al sistema de lectura / escritura devolvieran errores, y eso se hace con, exec 2>&-por ejemplo.
Peter Cordes
2
Pruébelo usted mismo: exec 3</dev/null; ls -l /proc/self/fdtenga en cuenta que fd 3 estará abierto de solo lectura en / dev / null. Luego ciérrelo nuevamente con exec 3<&-, y podrá ver (con ls -l /proc/$$/fdnuevamente) que su proceso de shell ya no tiene fd 3. (cerrar stdin con exec <&-puede ser útil en scripts, pero interactivamente es un cierre de sesión.)
Peter Cordes
@ PeterCordes Tienes toda la razón. Respuesta actualizada ¡Gracias!
jlliagre
1
Esta respuesta es excelente porque explica que los dos casos de uso de execla respuesta más votada actual solo hablan sobre un caso de uso y la otra respuesta de g_p solo habla sobre el otro caso de uso. Y esta respuesta es agradable y concisa / legible para un tema tan complejo.
Trevor Boyd Smith
33

Para entender exec, primero debes entender fork. Estoy tratando de mantenerlo corto.

  • Cuando llegas a una bifurcación en el camino, generalmente tienes dos opciones. Los programas de Linux llegan a esta bifurcación cuando llegan a una fork()llamada del sistema.

  • Los programas normales son comandos del sistema que existen en forma compilada en su sistema. Cuando se ejecuta dicho programa, se crea un nuevo proceso. Este proceso secundario tiene el mismo entorno que su padre, solo el número de ID del proceso es diferente. Este procedimiento se llama bifurcación .

  • La bifurcación proporciona una forma para que un proceso existente comience uno nuevo. Sin embargo, puede haber situaciones en las que un proceso secundario no sea parte del mismo programa que el proceso principal. En este caso execse utiliza. exec reemplazará el contenido del proceso actualmente en ejecución con la información de un programa binario.
  • Después del proceso de bifurcación, el espacio de direcciones del proceso secundario se sobrescribe con los nuevos datos del proceso. Esto se realiza mediante una llamada ejecutiva al sistema.
g_p
fuente
3
¿Puede explicar por qué execpuede redirigir una salida de script, como en el enlace que publiqué?
Becko
1
Encontré esto poco claro "Sin embargo, puede haber situaciones en las que un proceso secundario no sea parte del mismo programa que el proceso principal"
cdosborn
6

En bash, si lo haces help exec:

$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
    Replace the shell with the given command.

    Execute COMMAND, replacing this shell with the specified program.
    ARGUMENTS become the arguments to COMMAND.  If COMMAND is not specified,
    any redirections take effect in the current shell.

    Options:
      -a name   pass NAME as the zeroth argument to COMMAND
      -c        execute COMMAND with an empty environment
      -l        place a dash in the zeroth argument to COMMAND

    If the command cannot be executed, a non-interactive shell exits, unless
    the shell option `execfail' is set.

    Exit Status:
    Returns success unless COMMAND is not found or a redirection error occurs.

El bit relevante:

If COMMAND is not specified, any redirections take effect in the current shell.

execes un shell integrado , que es el equivalente de shell de la execfamilia de llamadas al sistema de las que habla G_P (y cuyas páginas de manual parece haber leído). Simplemente tiene la funcionalidad obligatoria POSIX de afectar el shell actual si no se especifica ningún comando.

muru
fuente