Como usar o Namedpipe como arquivo temporário?

Como usar o Namedpipe como arquivo temporário?

Um plugin vim que eu uso usa este script para passar algumas entradas para linters que não suportam leitura de stdin.

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"

No começo fiquei um pouco confuso sobre por que eles não usaram algo assim

some input | some_program /dev/stdin

Mas depois de tentar ghccomo linter, descobri que ele está reclamando de /dev/stdin dizendo algo sobre que não é um arquivo real (o que não é)

Então, eu me pergunto se posso usar o pipe nomeado em vez do arquivo temporário. A razão pela qual não estou muito satisfeito em gravar arquivos temporários é a integridade do SSD e se existe uma maneira melhor de fazer isso, por que não fazê-lo, certo?

Responder1

Não, os programas que rejeitam esses arquivos geralmente os rejeitam alegando que o arquivo não épesquisável(eles precisam acessar o conteúdo em deslocamentos arbitrários ou várias vezes após retroceder, etc.). Ou eles gostariam de abrir o arquivo várias vezes. Eles também podem querer reescrever (parte) do arquivo ou truncá-lo.

Os sem nome pipe(como com |e /dev/stdin) ou nomeados não fazem diferença em nenhum desses casos.

Na verdade, no Linux, /dev/stdinquando stdin é um pipe (nomeado ou não) se comporta exatamente como um pipe nomeado, o programa não seria capaz de diferenciá-lo /dev/stdinde um pipe nomeado real.

Em outros sistemas, não é exatamente o mesmo, mas, na verdade, abrir /dev/stdinum pipe nomeado fornecerá um descritor de arquivo para um pipe, algo que não pode ser procurado de qualquer maneira.

Então, você precisará criar o arquivo temporário. Observe que alguns shells facilitam isso. Com zsh, é apenas:

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

No Linux e com shells que usam arquivos temporários excluídos para documentos aqui (como bashe zshalgumas implementações de ksh), você pode fazer:

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

No entanto, isso pode alterar o conteúdo do arquivo se ele contiver caracteres NUL ou terminar em linhas vazias.

Observe que desde a versão 5, o bash torna o arquivo temporário here doc somente leitura, portanto, se o aplicativo precisar fazer modificações nesse arquivo, você deverá restaurar as permissões de gravação com:

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

Uma observação sobre esse while readloop desde que você perguntou.

Primeiro read -r, sem um nome de variável, a sintaxe não é válida sh. A shsintaxe é especificada pelo POSIX (ISO 9945, também IEEE Std 1003.1), assim como a Csintaxe é especificada pela ISO 9899.

Emessa especificação, você notará que isso readrequer um argumento de nome de variável. O comportamento quando você o omite énão especificadoe na prática variam de acordo com a shimplementação do intérprete.

bashshé o interpretador GNU , assim como gcco compilador GNU C. Ambos bashe gcctêm extensões sobre o que esses padrões especificam.

No caso de read, bashtrata read -rcomo se fosse IFS= read -r REPLY. Na especificação POSIX, IFS= read -r REPLYlê stdin até que um \ncaractere ou o final da entrada seja alcançado e armazena os caracteres lidos na $REPLYvariável e retorna com umsucessostatus de saída se um caractere de nova linha foi lido (uma linha completa) oufalhacaso contrário (como EOF antes da nova linha) e deixa o comportamento indefinido se os dados lidos contiverem caracteres NUL ou sequências de bytes que não formem caracteres válidos.

No caso de bash, armazenará os bytes lidos mesmo que não formem caracteres válidos e removerá os caracteres NUL.

read -ré como read -r REPLYem kshor zshe relata um erro em shells semelhantes a POSIX baseados yashem or .ash

O comportamento de echonão é especificado, a menos que seus argumentos não contenham caracteres de barra invertida e o primeiro não seja -n.

Então, para resumir, a menos que você conheça a shimplementação (e versão) específica com a qual está lidando, não poderá dizer o que está acontecendo.

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

vai fazer. No caso bashespecífico, ele armazenará stdin no temp_file apenas enquanto os dados não contiverem caracteres NUL, terminarem em um caractere de nova linha e nenhuma das linhas corresponder à ^-[neE]+$expressão regular estendida (e/ou dependendo do ambiente ou como bashfoi compilado como o shdo OS/X, não contém caracteres de barra invertida).

É tambémmuito ineficiente e não é a maneira como você processa texto em shells.

Aqui você quer:

cat > "$temp_file"

caté umcomando padrão, que quando não recebe nenhum argumento apenas despeja seu stdin em seu stdoutcomo é.

informação relacionada