Pseudo arquivos para dados temporários

76

Muitas vezes, desejo transmitir dados de strings relativamente curtos (podem ser várias linhas) para programas de linha de comando que aceitam apenas entradas de arquivos (por exemplo, wdiff) de maneira repetida. Claro que posso criar um ou mais arquivos temporários, salve a string lá e execute o comando com o nome do arquivo como parâmetro. Mas parece-me que este procedimento seria altamente ineficiente se os dados fossem realmente gravados no disco e também pudesse danificar o disco mais do que o necessário se eu repetisse este procedimento muitas vezes, por ex. se eu quiser alimentar linhas únicas de arquivos de texto longos para wdiff. Existe uma maneira recomendada de contornar isso, digamos, usando pseudo-arquivos como pipes para armazenar os dados temporariamente sem realmente gravá-los no disco (ou gravá-los somente se exceder um comprimento crítico). Note que wdiff leva dois argumentos e, até onde eu entendo, não será possível alimentar os dados fazendo algo como wdiff <"text" .

    
por highsciguy 06.02.2013 / 11:42

3 respostas

44

Use um canal nomeado . A título ilustrativo:

mkfifo fifo
echo -e "hello world\nnext line\nline 3" > fifo

O -e diz ao echo para interpretar corretamente o escape de nova linha ( \n ). Isso irá bloquear, ou seja, seu shell irá travar até que algo leia os dados do pipe.

Abra outro shell em algum lugar e no mesmo diretório:

cat fifo

Você vai ler o eco, que liberará o outro shell. Embora o pipe exista como um nó de arquivo no disco, os dados que passam por ele não o fazem; tudo acontece na memória. Você pode fazer o background ( & ) do eco.

O pipe tem um buffer de 64k (no linux) e, como um soquete, bloqueará o gravador quando estiver cheio, então você não perderá dados contanto que não mate prematuramente o gravador.

    
por 06.02.2013 / 12:46
106

No Bash, você pode usar a sintaxe de redirecionamento command1 <( command0 ) , que redireciona o stdout de command0 e o transmite a um command1 que recebe um nome de arquivo como um argumento de linha de comando. Isso se chama substituição do processo .

Alguns programas que usam argumentos de linha de comando de nome de arquivo realmente precisam de um arquivo real de acesso aleatório, portanto, essa técnica não funcionará para eles. No entanto, funciona bem com wdiff :

user@host:/path$ wdiff <( echo hello; echo hello1 ) <( echo hello; echo hello2 )
hello
[-hello1-]
{+hello2+}

No segundo plano, isso cria um FIFO, canaliza o comando dentro do <( ) para o FIFO e passa o descritor de arquivo do FIFO como um argumento. Para ver o que está acontecendo, tente usá-lo com echo para imprimir o argumento sem fazer nada com ele:

user@host:/path$ echo <( echo hello )
/dev/fd/63

A criação de um pipe nomeado é mais flexível (se você quiser escrever uma complicada lógica de redirecionamento usando vários processos), mas para muitos propósitos isso é suficiente e é obviamente mais fácil de usar.

Há também a sintaxe >( ) para quando você deseja usá-la como saída, por exemplo,

$ someprogram --logfile >( gzip > out.log.gz )

Veja também as dicas de redirecionamentos do Bash para as técnicas relacionadas.

    
por 07.02.2013 / 02:02
6

O wdiff é um caso especial devido a exigir 2 argumentos de nome de arquivo, mas para todos os comandos que requerem apenas 1 argumento e que teimosamente se recusam a aceitar qualquer coisa além de um argumento de nome de arquivo, existem 2 opções:

  • O nome do arquivo '-' (isto é, um sinal de menos) funciona cerca de metade do tempo. Parece depender do comando em questão e se o desenvolvedor do comando intercepta esse caso e o manipula conforme o esperado. por exemplo,

    $> ls | cat -

  • Existe um arquivo psuedo chamado / dev / stdin que existe no linux e pode ser usado se um nome de arquivo for absolutamente requerido por um comando. É mais provável que isso funcione, pois não requer nenhum tratamento especial de nome de arquivo do comando. Se um método fifo funciona, ou o bash processo de substituição funciona, então isso também deve funcionar e não é específico do shell. por exemplo,

    $> ls | cat /dev/stdin

por 17.11.2014 / 16:01

Tags