GNU/Linux >> Tutoriales Linux >  >> Linux

¿Crear archivo temporal frente a sustitución de procesos frente a expansión variable?

<(cmd) es un ksh función que también se encuentra hoy en día en zsh y bash llamado sustitución de proceso .

En sistemas que admiten /dev/fd/n o /proc/self/fd/n , se implementa con canalizaciones y, cuando no, con canalizaciones temporales con nombre. En cualquier caso, es una forma de tubería que es un mecanismo de comunicación entre procesos.

cmd1 <(cmd2)

Se puede escribir (con tuberías normales):

{ cmd2 4<&- | 3<&0 <&4 4<&- cmd1 /dev/fd/3; } 4<&0

O (con canalizaciones con nombre):

mkfifo /tmp/named_pipe
cmd2 > /tmp/named_pipe & cmd1 /tmp/named_pipe

Es decir, ambos comandos se inician simultáneamente y se comunican con una tubería. Usualmente usarías cmd2 | cmd1 para eso, pero la sustitución de procesos suele ser para aquellos casos en los que cmd1 solo puede tomar entradas de un nombre de archivo y no de una entrada estándar o cuando se necesita más de una entrada como en diff <(cmd1) <(cmd2) .

No hay ningún límite que lo afecte aparte de los generales, como el número de procesos, el tiempo de CPU o la memoria.

El PIPEBUF informado por algunas implementaciones de ulimit como bash y algunas implementaciones de ksh no es un límite, sino el tamaño máximo para el que se garantiza que una escritura en una tubería sea atómica, por lo que es irrelevante aquí. El tamaño de la tubería en sí (64kB en Linux según lo informado por @dsmsk80) no es realmente un límite en sí mismo. Solo dice que es tanto cmd2 puede escribir en la canalización incluso después de cmd1 ha dejado de leerlo.

Sin embargo, hay una limitación en eso cmd1 solo puede leer de ese archivo. Debido a que es una canalización, no puede escribir en ese archivo ni buscar hacia adelante y hacia atrás en el archivo.

zsh tiene una tercera forma de sustitución de comandos usando archivos temporales regulares:

cmd1 =(cmd2)

llamadas cmd1 con un archivo temporal que contiene la salida de cmd2 . En ese caso cmd1 se ejecuta después cmd2 en lugar de simultáneamente. El límite en el tamaño de los archivos puede alcanzarse allí.

No conozco ningún shell que implemente un <<<(...) operador. Sin embargo, hay un <<< operador en zsh (inspirado en el mismo operador en el puerto Unix de rc ) también se encuentra en versiones recientes de ksh93 y bash . Es una variación del << operador heredoc llamado herestring.

en:

cmd <<< something

Que es lo mismo que el estándar:

cmd << EOF
something
EOF

El shell crea un archivo temporal con something\n como el contenido y lo alimenta como entrada estándar a un nuevo proceso, desvincula ese archivo y ejecuta cmd en ese nuevo proceso. Nuevamente, ese es un archivo normal, por lo que se puede alcanzar el límite en el tamaño máximo de un archivo.

Ahora puedes combinar el <<< operador con $(...) (sustitución de comandos) para emular de alguna manera zsh de =(...) operador en bash y ksh93 :

cmd1 <<<"$(cmd2)"

Ejecutaría cmd2 con stdout redirigido a una tubería. En el otro extremo de la tubería, el shell lee la salida de cmd2 y lo almacena menos los caracteres de nueva línea finales y con un carácter de nueva línea agregado en un archivo temporal y llama a cmd1 con ese archivo temporal abierto para leer como stdin (tenga en cuenta que hay otra limitación en el sentido de que no funcionará si cmd2 la salida contiene caracteres NUL).

Ser como =(...) , tendrías que escribirlo:

cmd1 /dev/fd/3 3<<<"$(cmd3)"

Tenga en cuenta que el shell debe leer la salida completa de cmd3 en la memoria antes de escribirla en el archivo temporal, por lo que, además del tamaño máximo del archivo, también puede alcanzar el límite de uso de la memoria.

También tenga en cuenta que desde la versión 5, bash quita los permisos de escritura al archivo temporal antes de llamar a cmd1 , por lo que si necesita cmd1 para poder modificar ese archivo, debe solucionarlo con:

{
  chmod u+w /dev/fd/3 && # only needed in bash 5+
  cmd1 /dev/fd/3
} 3<<<"$(cmd3)"

Sustitución del proceso Bash en forma de <(cmd) y >(cmd) se implementa con canalizaciones con nombre si el sistema las admite. El comando cmd se ejecuta con su entrada/salida conectada a una tubería. Cuando corres, p. cat <(sleep 10; ls) puede encontrar la tubería creada en el directorio /proc/pid_of_cat/fd . Esta canalización con nombre se pasa como argumento al comando actual (cat ).

La capacidad de almacenamiento intermedio de una tubería se puede estimar con un uso engañoso de dd comando que envía cero datos a la entrada estándar de sleep comando (que no hace nada). Aparentemente, el proceso se suspenderá por un tiempo, por lo que el búfer se llenará:

(dd if=/dev/zero bs=1 | sleep 999) &

Espere un segundo y luego envíe USR1 señal al dd proceso:

pkill -USR1 dd

Esto hace que el proceso para imprimir estadísticas de E/S:

65537+0 records in
65536+0 records out
65536 bytes (66 kB) copied, 8.62622 s, 7.6 kB/s

En mi caso de prueba, el tamaño del búfer es 64kB (65536B ).

¿Cómo se usa <<<(cmd)? ¿expansión? Soy consciente de que es una variación de los documentos aquí que se expande y pasa al comando en su entrada estándar.

Con suerte, arrojaré algo de luz sobre la pregunta sobre el tamaño. En cuanto a la velocidad, no estoy tan seguro, pero supongo que ambos métodos pueden ofrecer un rendimiento similar.


Linux
  1. Una guía para principiantes para crear redireccionamientos en un archivo .htaccess

  2. Creación de un archivo CSR de certificado web.

  3. ¿Cómo determinar qué proceso está creando un archivo?

  4. ¿Cómo aplazar la expansión variable?

  5. ¿La salida de sustitución del proceso está fuera de orden?

Filtrando tcpdump:creando orden a partir del caos

¿Sustitución de proceso y tubería?

¿Por qué la sustitución del proceso Bash no funciona con algunos comandos?

Sustitución de variables de entorno en sed

Definición de una variable con o sin exportación

Crear un demonio en Linux