Como usar namedpipe como arquivo temporário?

5

Um plugin vim que eu uso usa este script para passar alguma entrada 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, eu estava um pouco confuso sobre por que eles não usaram algo assim

some input | some_program /dev/stdin

Mas depois de tentar ghc como linter eu descobri que está reclamando sobre / dev / stdin dizendo algo sobre isso não é arquivo real (o que não é)

Então, pergunto-me se posso usar namedpipe em vez de arquivo temporário. A razão pela qual eu não estou satisfeito com a gravação de arquivos temporários é a integridade do SSD e se há uma maneira melhor de fazer isso, por que não fazer isso, certo?

    
por user1685095 05.11.2016 / 20:05

1 resposta

6

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

O nome pipe (como | e /dev/stdin ) ou os nomes não fazem diferença em nenhum desses casos.

Na verdade, no Linux, /dev/stdin quando stdin é pipe (nomeado ou não) se comporta exatamente como um pipe nomeado, o programa não seria capaz de diferenciar esse /dev/stdin de um pipe nomeado real.

Em outros sistemas, não é exatamente o mesmo, mas, na verdade, abrir /dev/stdin ou um pipe nomeado fornecerá a você um descritor de arquivo para um pipe, algo que não é possível de nenhuma maneira.

Então, você precisará criar o arquivo temporário. Note que algumas conchas tornam isso mais fácil. Com zsh , é apenas:

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

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

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

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

Uma observação sobre o loop while read desde que você perguntou.

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

Em essa especificação , você notará que read requer um argumento de nome de variável . O comportamento quando você omitir é não especificado e, na prática, varia com a implementação sh do intérprete.

bash é o interpretador do GNU sh , como gcc é o compilador C do GNU. Tanto bash quanto gcc têm extensões sobre o que esses padrões especificam.

No caso de read , bash trata read -r como se fosse IFS= read -r REPLY . Na especificação POSIX, IFS= read -r REPLY lê stdin até que um caractere \n ou o final da entrada seja atingido e armazena os caracteres lidos na variável $REPLY e retorna com um status de saída sucesso se um caractere de nova linha foi lido (uma linha completa) ou falha caso contrário (como EOF antes da nova linha) e deixa o comportamento indefinido se os dados lidos contiverem caracteres NUL ou seqüências de bytes que não formam caracteres válidos .

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

read -r é como read -r REPLY em ksh ou zsh e relata um erro em yash ou ash baseado em POSIX.

O comportamento de echo nã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ê saiba a implementação% (e versão) do sh com a qual você está lidando, você não pode dizer o que

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

fará. No caso de bash especificamente, ele armazenará stdin no arquivo_temp, contanto que os dados não contenham caracteres NUL, terminem em um caractere de nova linha e nenhuma das linhas corresponda à expressão regular estendida ^-[neE]+$ (e / ou ou dependendo do ambiente ou como bash foi compilado como sh do OS / X, não contém caracteres de barra invertida).

Também é muito ineficiente e não é a maneira como você processa texto em shells .

Aqui, você quer:

cat > "$temp_file"

cat é um comando padrão , que, quando não recebe nenhum argumento, apenas descarta stdin em seu stdout como está .

    
por 05.11.2016 / 20:28