¿Cómo utilizar Namepipe como archivo temporal?

¿Cómo utilizar Namepipe como archivo temporal?

Un complemento de vim que uso utiliza este script para pasar algunas entradas a linters que no admiten la lectura desde la entrada estándar.

set -eu

# All of the following arguments are read as command to run.
file_extension="$1"
shift

temp_dir=$(mktemp -d 2>/dev/null || mktemp -d -t 'ale_linter')
temp_file="$temp_dir/file$file_extension"
trap 'rm -r "$temp_dir"' EXIT

while read -r; do
  echo "$REPLY" >> "$temp_file"
done

"$@" "$temp_file"

Al principio estaba un poco confundido acerca de por qué no habían usado algo así.

some input | some_program /dev/stdin

Pero después de intentarlo ghccomo linter, descubrí que se queja de que /dev/stdin dice algo acerca de que no es un archivo real (que no lo es).

Entonces me pregunto si puedo usar la canalización con nombre en lugar de un archivo temporal. La razón por la que no estoy del todo satisfecho con escribir en archivos temporales es el estado del SSD y si hay una mejor manera de hacerlo, ¿por qué no hacerlo, verdad?

Respuesta1

No, los programas que rechazan esos archivos generalmente los rechazan basándose en que el archivo no esbuscable(Necesitan acceder al contenido en desplazamientos arbitrarios, o varias veces después de rebobinar, etc.). O querrían abrir el archivo varias veces. Es posible que también quieran reescribir (parte de) el archivo o truncarlo.

Los que no tienen nombre pipe(como con |y /dev/stdin) o los que tienen nombre no hacen ninguna diferencia en ninguno de esos casos.

En realidad, en Linux, /dev/stdincuando la entrada estándar es una tubería (con nombre o no) se comporta exactamente como una tubería con nombre, el programa no podría diferenciarla /dev/stdinde una tubería con nombre real.

En otros sistemas, no es exactamente lo mismo, pero, en efecto, abrir /dev/stdinuna tubería con nombre le proporcionará un descriptor de archivo para una tubería, algo que no se puede buscar de ninguna manera.

Entonces, necesitarás crear el archivo temporal. Tenga en cuenta que algunos caparazones lo hacen más fácil. Con zsh, es solo:

#! /bin/zsh -
"$@" =(cat)

En Linux y con shells que utilizan archivos temporales eliminados para estos documentos (como bashy zshalgunas implementaciones de ksh), puede hacer:

#! /bin/bash -
"$@" /dev/fd/3 3<< EOF
$(cat)
EOF

Sin embargo, eso puede alterar el contenido del archivo si contiene caracteres NUL o termina en líneas vacías.

Tenga en cuenta que desde la versión 5, bash hace que el archivo temporal aquí doc sea de solo lectura, por lo que si la aplicación necesita realizar modificaciones en ese archivo, deberá restaurar los permisos de escritura con:

#! /bin/bash -
{
  chmod u+w /dev/fd/3 && # only needed in bash 5+
    "$@" /dev/fd/3
} 3<< EOF
$(cat)
EOF

Una nota sobre ese while readbucle desde que preguntaste.

Primero read -r, sin un nombre de variable no es shuna sintaxis válida. La shsintaxis está especificada por POSIX (ISO 9945, también IEEE Std 1003.1) al igual que la Csintaxis está especificada por ISO 9899.

Enesa especificación, notarás que readrequiere un argumento de nombre de variable. El comportamiento cuando lo omites esno especificadoy en la práctica varían con la shimplementación del intérprete.

bashes el shintérprete GNU, al igual gccque el compilador GNU C. Ambos bashy gcctienen extensiones sobre lo que especifican esos estándares.

En el caso de read, bashlo trata read -rcomo si lo fuera IFS= read -r REPLY. En la especificación POSIX, lee la entrada estándar hasta que se alcanza IFS= read -r REPLYun carácter o el final de la entrada y almacena los caracteres leídos en la variable y regresa con un\n$REPLYéxitoestado de salida si se leyó un carácter de nueva línea (una línea completa) ofallade lo contrario (como EOF antes de la nueva línea) y deja el comportamiento indefinido si los datos leídos contienen caracteres NUL o secuencias de bytes que no forman caracteres válidos.

En el caso de bash, almacenará los bytes leídos incluso si no forman caracteres válidos y eliminará los caracteres NUL.

read -res como read -r REPLYen kshor zshe informa un error en shells tipo POSIX basados ​​en yashor .ash

El comportamiento de echono está especificado a menos que sus argumentos no contengan caracteres de barra invertida y el primero no sea -n.

Entonces, para resumir, a menos que conozca la shimplementación (y la versión) particular con la que está tratando, no podrá saber qué

while read -r; do
  echo "$REPLY" >> "$temp_file"
done

servirá. En el caso bashespecífico, almacenará stdin en temp_file solo siempre que los datos no contengan caracteres NUL, terminen en un carácter de nueva línea y ninguna de las líneas coincida con la ^-[neE]+$expresión regular extendida (y/o dependiendo del entorno o (cómo bashse compiló como shOS/X, no contiene caracteres de barra invertida).

Es tambiénmuy ineficiente y no es la forma en que procesas el texto en shells.

Aquí quieres:

cat > "$temp_file"

cates uncomando estándar, que cuando no se le da ningún argumento simplemente descarga su entrada estándar en su salida estándarcomo es.

información relacionada