¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Programación shell en Unix/Linux
  3. Otros aspectos de los mecanismos internos del shell
Extrait - Programación shell en Unix/Linux ksh, bash, estándar POSIX (con ejercicios corregidos) (5ª edición)
Extractos del libro
Programación shell en Unix/Linux ksh, bash, estándar POSIX (con ejercicios corregidos) (5ª edición)
1 opinión
Volver a la página de compra del libro

Otros aspectos de los mecanismos internos del shell

Presentación

Este capítulo está dirigido a lectores que quieran entender en profundidad los mecanismos internos de ciertos comandos. Por lo tanto, leer este capítulo no es indispensable para usar el shell.

Redirigir los descriptores 1 y 2 al mismo archivo

Para enviar la salida estándar y la salida de error estándar al mismo archivo, se debe utilizar una sintaxis especial. Esto es lo que no se debe escribir, junto con la razón de por qué no funciona.

Sintaxis incorrecta

$ comando 1> archivo 2> archivo  
$ comando 1> archivo 2>> archivo 

El problema no es que se abra el mismo archivo dos veces (lo cual es perfectamente legal dentro del mismo proceso), sino que hay un offset (posición actual en el archivo) asociado con cada apertura. ¿Cuáles son las consecuencias?

  • La secuencia de los resultados en el archivo no será necesariamente representativa del orden en el que se desarrollaron los eventos.

  • Los resultados reportados a través de los descriptores 1 y 2, se pueden superponer.

Las figuras 1 y 2 muestran el mecanismo interno asociado con el siguiente comando: 

$ find / -name passwd 1> resu 2> resu 

Primera etapa (ver Figura 1)

Procesamiento de la redirección 1>resu:

El shell abre el archivo resu (el archivo se crea con un tamaño de 0) y lo asocia al descriptor 1 (1), (2), (3), (4), (5). Cuando un proceso abre un archivo, siempre hay un registro asignado en la tabla de archivos abiertos del kernel (2) (que agrupa todos los archivos abiertos en el sistema en un momento dado). El registro contiene el modo de apertura del archivo (aquí en modo escritura), así...

Agrupar comandos con paréntesis

En la mayoría de los casos, los paréntesis se utilizan para agrupar comandos.

Sintaxis

(cmdo1; cmdo2; cmdo3) 

Con los paréntesis, siempre se crea un shell hijo y es este el que procesa la línea de comandos (con duplicaciones posteriores si es necesario).

Los comandos entre paréntesis se ejecutan desde un shell hijo.

Primer ejemplo

$ (date ; ls) > resultado   
$ cat resultado   
vie 28 ene 05:21:36 CET 2022  
FIC   
archivo   
$ 
  

Las figuras 4, 5 y 6 muestran el mecanismo interno asociado. El shell actual (PID=201) se duplica (1). El shell hijo (PID=205) primero se encarga de la redirección (2), después se duplica para la ejecución del comando externo date (5). Cuando este último ha terminado (7), se duplica de nuevo para ejecutar ls (8). Gracias al mecanismo de herencia, ambos comandos utilizan el mismo offset (3). Por lo tanto, las escrituras en el archivo se suceden entre sí.

images/cap11_pag9.png

Figura 4: Primer ejemplo de agrupación con paréntesis - Primera etapa

images/cap11_pag10.png

Figura 5: Primer ejemplo de agrupación con paréntesis - Segunda etapa

images/cap11_pag11.png

Figura 6: Primer ejemplo de agrupación con paréntesis - Tercera etapa

Segundo ejemplo

El directorio actual los comandos pwd y ls es /tmp:

$ pwd   
/home/cristina  
$ (cd /tmp ; pwd ; ls) >...

Agrupar comandos con llaves

Sintaxis

{ cmdo1 ; cmdo2 ; cmdo3 ; } 

El shell actual procesa la línea de comandos (con duplicaciones posteriores si es necesario).

Primer ejemplo

$ { date; ls ; } > resultado 

Las figuras 9, 10, 11 y 12 representan el mecanismo interno asociado a las llaves. El shell de trabajo guarda sus asociaciones actuales descriptor-archivo (1), procesa la redirección solicitada (2), se duplica para la ejecución del comando externo date (5) y luego, cuando el comando externo ha terminado (7), se duplica nuevamente para ejecutar ls (8). Cuando terminan los comandos, el shell de primer nivel toma el control (10) y restaura su entorno descriptor-archivo (11).

images/cap11_pag15.png

Figura 9: Primer ejemplo de agrupación con llaves - Primera etapa

images/cap11_pag16.png

Figura 10: Primer ejemplo de agrupación con llaves - Segunda etapa

images/cap11_pag17.png

Figura 11: Primer ejemplo de agrupación con llaves - Tercera etapa

images/cap11_pag17_b.png

Figura 12: Primer ejemplo de agrupación con llaves - Cuarta etapa

Segundo ejemplo

Aquí, se modificará el entorno del shell de primer nivel, lo que no es necesariamente muy interesante:

$ pwd    
/home/cristina  
$    
$ { cd /tmp ; pwd ; ls ; } > listaarch   
$   
$ cat listaarch   
/tmp   
dcopNYSrKn   
listatmp   
$ pwd   
/tmp   
$ 

Las figuras...

Interpretación de un script mediante un shell hijo

A menos que exista una sintaxis especial, un script es ejecutado por un shell hijo, que mantiene intacto el entorno del shell de trabajo.

Consideremos el siguiente script primero.sh:

$ nl primero.sh 
 1 pwd  
 2 cd /tmp 
 3 pwd 
 4 ls  
$ 

Echemos un vistazo más de cerca a la ejecución de este script:

$ pwd   
/home/cristina  
   
$ primero.sh   
/home/cristina   
/tmp   
f1 f2 f3   
   
$ pwd   
/home/cristina 

Cuando el script termina de ejecutarse, el valor del directorio actual no ha cambiado. Dado que un script de shell es un comando externo, lo ejecuta un shell hijo. Las figuras 15, 16 y 17 muestran los detalles de la ejecución del script primero.sh.

images/cap11_pag20.png

Figura 15: Mecanismo interno implementado al ejecutar un script de shell - Primera etapa

(1)

Antes de ejecutar el script, el usuario muestra el valor del directorio actual. Debido a que el comando pwd es un comando interno, lo ejecuta el shell actual (PID=201). Por lo tanto, el resultado del comando es /home/cristina.

(2)

Ejecución del script primero. Dado que un script de shell es un comando externo, el shell actual se duplica. Por lo tanto, el script será interpretado por el shell hijo (PID=205). El shell hijo hereda el directorio actual de su padre....