¿Cómo funciona `cat <> file`?

42

cat < fileimprime el contenido del archivo en stdout.

cat > filelee stdin hasta que se detecta Ctrl+ Dy el texto de entrada se escribe en el archivo .

cat <> file, al menos en mi versión de Bash, imprime felizmente el contenido del archivo (sin error), pero no modifica el archivo ni actualiza la marca de tiempo de modificación.

¿Cómo justifica el estándar Bash lo que aparentemente se ignora >en la tercera declaración y, lo que es más importante, está haciendo algo?

Qix
fuente

Respuestas:

47

Bash utiliza <>para crear un descriptor de archivo de lectura y escritura :

El operador de redireccionamiento

[n]<>word

hace que el archivo cuyo nombre es la expansión de la palabra se abra para leer y escribir en el descriptor de archivo n, o en el descriptor de archivo 0 si n no se especifica. Si el archivo no existe, se crea.

cat <> fileabre filelectura-escritura y lo vincula al descriptor 0 (entrada estándar). Es esencialmente equivalente a < filecualquier programa escrito con sensatez, ya que es probable que nadie intente escribir en la entrada estándar ordinariamente, pero si lo hiciera, podría hacerlo.

Puede escribir un simple programa en C para probarlo directamente, write(0, "hello", 6)lo escribirá helloa filetravés de una entrada estándar.

<>También debería funcionar en cualquier otro shell compatible con POSIX con el mismo efecto.

Michael Homer
fuente
1
Escribiendo ... a stdin? ... ¿Hay algún caso de uso válido para esto?
Qix
3
Por otra parte, no puedo pensar en ninguna buena. Dar un descriptor explícito ( 4<>file) es útil, y supongo que 0 es un valor predeterminado tan bueno como cualquier otro cuando lo omites. Leer desde stdout no es mejor.
Michael Homer
55
<>También es útil en algunos sistemas (como Linux) para abrir canalizaciones con nombre sin bloquear hasta que otro proceso lo abra para escribir.
Stéphane Chazelas
1
@Qix: Bueno, escribir (0, "Contraseña:", 10) es una buena manera de solicitar una contraseña si tiene la intención de solicitar cualquier tipo de tty. Estoy acostumbrado a verlo solo en stderr, pero no hay ninguna razón en particular, la misma técnica no funciona en stdin.
Joshua
3
@Qix: de la justificación de POSIX : el <>operador podría ser útil para escribir una aplicación que funcionara con varios terminales y ocasionalmente quisiera iniciar un shell. Ese shell a su vez no podría ejecutar aplicaciones que se ejecutan desde un terminal de control ordinario a menos que pueda hacer uso de <>... como ... el localizador more, que se lee desde un error estándar para obtener sus comandos, por lo que la entrada estándar y la salida estándar Ambos están disponibles para su uso habitual. cat food | more - >/dev/tty03 2<>/dev/tty03
mikeserv
38

<> fileabre el archivo (en el descriptor de archivo 0 (entrada estándar) de forma predeterminada, al igual que <) en + lectura y escritura modo sin truncamiento y crear el archivo si no existía previamente .

Eso corresponde a los O_RDWR|O_CREATindicadores pasados ​​a la open()llamada al sistema. Por el contrario <es O_RDONLYy >es O_WRONLY|O_CREAT|O_TRUNCy >> O_WRONLY|O_CREAT|O_APPEND.

Tener stdin escribible no suele ser útil ya que las aplicaciones generalmente no escriben en su stdin. Las aplicaciones generalmente no esperan leer y escribir en un descriptor de archivo que reciben al inicio; Por lo general, leen de stdin (o un descriptor de archivo que abren) y escriben en stdout o stderr (o un descriptor de archivo que abren).

<> puede tener sus usos:

  • Es posible que prefiera cat <> filesobre cat < filesi no desea que el comando falle si fileno existe, pero un vacío filecreado en su lugar.
  • El aspecto no truncado de <>hace que sea útil sobrescribir archivos en su lugar. Sin embargo, en ese caso, generalmente no lo usa en el descriptor de archivo 0:

    printf xxx 1<> file

    reemplaza los primeros 3 bytes de filecon xxx.

  • En algunos sistemas como Linux, <>en una tubería con nombre (FIFO) abre la tubería con nombre sin bloquear (sin esperar a que algún otro proceso abra el otro extremo), y garantiza que la estructura de la tubería se mantenga viva. Por ejemplo en:

    mkfifo pipe; sed 's/foo/bar/g' <> pipe

    sedmaneja datos entrantes de cualquier número de otros procesos que le escriben y nunca los ve eof.

Stéphane Chazelas
fuente
1
Tenga en cuenta que en AT&T ksh93, el valor <>predeterminado es 1<>(stdout) en lugar de 0<>(stdin). Este es un error de cumplimiento POSIX que informé y se solucionará en la próxima versión. github.com/att/ast/issues/75 Pero hasta que las versiones actuales de ksh93 caigan en desuso, debe incluir el número de descriptor de archivo para usarlo de forma <>portátil.
Martijn Dekker
@MartijnDekker, lo sé, fui yo quien te lo contó en primer lugar ;-). Tenga en cuenta que es solo para ksh93t + (donde el comportamiento cambió) y superiores.
Stéphane Chazelas
¿Cuáles son (o fueron) los sistemas a diferencia de Linux donde mkfifo fifo; exec 3<>fifose bloquearían?
Tío Billy