En
./binary < file
binary
'stdin' es el archivo abierto en modo de solo lectura. Tenga en cuenta que bash
no lee el archivo en absoluto, solo lo abre para leerlo en el descriptor de archivo 0 (stdin) del proceso en el que se ejecuta binary
.
En:
./binary << EOF
test
EOF
Dependiendo del shell, binary
el stdin del archivo será un archivo temporal eliminado (AT&T ksh, zsh, bash ...) que contiene test\n
lo que el shell o el extremo de lectura de una tubería han puesto allí ( dash
, yash
; y el shell escribe test\n
en paralelo en el otro extremo de la tubería). En su caso, si está utilizando bash
, sería un archivo temporal.
En:
cat file | ./binary
Dependiendo del shell, binary
la entrada estándar será el extremo de lectura de una tubería o un extremo de un par de zócalos donde la dirección de escritura se ha cerrado (ksh93) y cat
está escribiendo el contenido file
en el otro extremo.
Cuando stdin es un archivo normal (temporal o no), es buscable. binary
puede ir al principio o al final, rebobinar, etc. También puede mapearlo, hacer algo ioctl()s
como FIEMAP / FIBMAP (si se usa en <>
lugar de <
, podría truncar / perforar agujeros, etc.).
Por otro lado, las tuberías y los pares de tomas son un medio de comunicación entre procesos, no hay mucho que binary
pueda hacer además read
de los datos (aunque también hay algunas operaciones como algunas específicas de tuberías ioctl()
que podría hacer en ellos y no en los archivos normales) .
La mayoría de las veces, es la capacidad que falta para seek
que hace que las aplicaciones a fallar / quejan cuando se trabaja con tubos, pero podría ser cualquiera de las otras llamadas al sistema que son válidos en los archivos normales, pero no en los diferentes tipos de archivos (como mmap()
, ftruncate()
, fallocate()
) . En Linux, también hay una gran diferencia en el comportamiento cuando se abre /dev/stdin
mientras el fd 0 está en una tubería o en un archivo normal.
Existen 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 (regular en el primer caso, canalización en el segundo) se proporciona como un argumento de ruta unzip
y se unzip
abre por sí mismo (generalmente en fd que no sea 0) en lugar de heredar un fd ya abierto por el padre. No lee archivos zip de su stdin. stdin se usa principalmente para la interacción del usuario.
Si ejecuta el binary
suyo sin redireccionamiento en el indicador de un shell interactivo que se ejecuta en un emulador de terminal, binary
el stdin se heredará de su padre, el shell, que a su vez lo habrá heredado de su padre, el emulador de terminal y será un Dispositivo pty abierto en modo lectura + escritura (algo así como /dev/pts/n
).
Esos dispositivos tampoco son buscables. Por lo tanto, si binary
funciona bien al tomar la entrada desde el terminal, posiblemente el problema no sea buscar.
Si ese 14 está destinado a ser un error (un código de error establecido por las llamadas fallidas del sistema), entonces en la mayoría de los sistemas, eso sería EFAULT
( Dirección incorrecta ). La read()
llamada del sistema fallará con ese error si se le pide que lea en una dirección de memoria que no se puede escribir. Eso sería independiente de si el fd lee los datos desde puntos a una tubería o 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 saber sin saber más sobre la aplicación. Ejecutarlo bajo strace
(o truss
/ tusc
equivalente en su sistema) podría ayudarnos a ver cuál es la llamada del sistema, si es que alguna falla 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 al final del archivo 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é fallos dado el búfer no es válido.