shell – ¿Cuál es la diferencia entre "archivo cat | ./binary" y "./binary <file"?

Pregunta:

Tengo un binario (que no puedo modificar) y puedo hacer:

./binary < file

Yo tambien puedo hacer:

./binary << EOF
> "line 1 of file"
> "line 2 of file"
...
> "last line of file"
> EOF

Pero

cat file | ./binary

me da un error. No sé por qué no funciona con una pipa. En los 3 casos, el contenido del archivo se da a la entrada estándar de binario (de diferentes maneras):

  1. bash lee el archivo y lo da a stdin de binario
  2. bash lee líneas desde stdin (hasta EOF) y lo da a stdin del binario
  3. cat lee y coloca las líneas del archivo en stdout, bash las redirige a stdin del binario

El binario no debería notar la diferencia entre esos 3 hasta donde yo lo entendí. ¿Alguien puede explicar por qué el tercer caso no funciona?

Por cierto: el error dado por el binario es:

20170116/125624.689 – U3000011 No se pudo leer el archivo de script '', código de error '14'.

Pero mi pregunta principal es, ¿cómo hay una diferencia para cualquier programa con esas 3 opciones?

Aquí hay algunos detalles adicionales: Lo intenté nuevamente con strace y, de hecho, hubo algunos errores ESPIPE (búsqueda ilegal) de lseek seguido de EFAULT (dirección incorrecta) de la lectura justo antes del mensaje de error.

El binario que intenté controlar con un script ruby ​​(sin usar archivos temporales) es parte del callapi de Automic (UC4) .

Respuesta:

En

./binary < file

stdin de binary es el archivo que se abre en modo de solo lectura. Tenga en cuenta que bash no lee el archivo en absoluto, solo lo abre para leer en el descriptor de archivo 0 (stdin) del proceso en el que ejecuta el binary .

En:

./binary << EOF
test
EOF

Dependiendo del shell, el stdin de binary será un archivo temporal eliminado (AT&T ksh, zsh, bash …) que contiene test\n como lo pone el shell o el extremo de lectura de una tubería ( dash , yash ; y el shell escribe test\n en paralelo en el otro extremo de la tubería). En su caso, si está usando bash , sería un archivo temporal.

En:

cat file | ./binary

Dependiendo del shell, el stdin de binary será el extremo de lectura de una tubería o un extremo de un par de conectores donde la dirección de escritura se ha cerrado (ksh93) y cat está escribiendo el contenido del file en el otro extremo.

Cuando stdin es un archivo normal (temporal o no), se puede buscar. binary puede ir al principio o al final, rebobinar, etc. También puede mmap, hacer algunos ioctl()s como FIEMAP / FIBMAP (si usa <> lugar de < , podría truncarlo / perforarlo, etc.).

Por otro lado, las tuberías y los pares de conectores son un medio de comunicación entre procesos, no hay mucho que pueda hacer el binary además de read los datos (aunque también hay algunas operaciones como algunos ioctl() específicos de tubería que podría hacer en ellos y no en archivos normales).

La mayoría de las veces, es la falta de capacidad de seek que hace que las aplicaciones fallen / se quejen cuando se trabaja con tuberías, pero podría ser cualquiera de las otras llamadas al sistema que son válidas en archivos normales pero no en diferentes tipos de archivos (como mmap() , ftruncate() , fallocate() ). En Linux, también hay una gran diferencia en el comportamiento cuando abre /dev/stdin mientras el fd 0 está en una tubería o en un archivo normal.

Hay muchos comandos que solo pueden tratar con archivos buscables , pero cuando ese es el caso, generalmente no es para los archivos abiertos en su stdin.

$ unzip -l file.zip
Archive:  file.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
       11  2016-12-21 14:43   file
---------                     -------
       11                     1 file
$ unzip -l <(cat file.zip)
     # more or less the same as cat file.zip | unzip -l /dev/stdin
Archive:  /proc/self/fd/11
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of /proc/self/fd/11 or
        /proc/self/fd/11.zip, and cannot find /proc/self/fd/11.ZIP, period.

unzip necesita leer el índice almacenado al final del archivo, y luego buscar dentro del archivo para leer los miembros del archivo. Pero aquí, el archivo (normal en el primer caso, pipe en el segundo) se proporciona como un argumento de ruta para unzip , y unzip abre por sí mismo (generalmente en fd distinto de 0) en lugar de heredar un fd ya abierto por la persona que llama. No lee archivos zip de su stdin. stdin se utiliza principalmente para la interacción del usuario.

Si ejecuta ese binary sin redireccionamiento en el indicador de un shell interactivo que se ejecuta en un emulador de terminal, entonces el stdin del binary se heredará de su llamador, el shell, que a su vez lo habrá heredado de su llamador, el emulador de terminal y lo hará. ser un dispositivo pty abierto en modo lectura + escritura (algo así como /dev/pts/n ).

Esos dispositivos tampoco se pueden buscar. Por lo tanto, si el binary funciona bien al recibir datos del terminal, posiblemente el problema no se trate de buscar.

Si ese 14 está destinado a ser un errno (un código de error establecido por llamadas al sistema EFAULT ), entonces en la mayoría de los sistemas, sería EFAULT ( dirección incorrecta ). La llamada al sistema read() fallaría con ese error si se le pidiera leer en una dirección de memoria que no se puede escribir. Eso sería independiente de si el fd leerá los datos de los puntos a una tubería o un archivo normal y generalmente indicaría un error 1 .

binary posiblemente determina el tipo de archivo abierto en su stdin (con fstat() ) y se encuentra con un error cuando no es un archivo normal ni un dispositivo tty.

Difícil de decir sin saber más sobre la aplicación. Ejecutarlo bajo strace (o el equivalente de truss / tusc en su sistema) podría ayudarnos a ver cuál es la llamada al sistema, si hay alguna que esté fallando aquí.


1 El escenario previsto por Matthew Ife en un comentario a su pregunta suena muy plausible aquí. Citando a él:

Sospecho que está buscando hasta el final del archivo para obtener un tamaño de búfer para leer los datos, manejando mal el hecho de que la búsqueda no funciona e intentando asignar un tamaño negativo (no manejando un malloc malo). Pasar el búfer para leer qué fallas dado el búfer no es válido.

Leave a Comment

Your email address will not be published.

Scroll to Top

istanbul avukat

-

web tasarım