Alterando arquivos dinamicamente no Linux (escrevendo para o arquivo de entrada em um pipe)

6

Como alterar um arquivo na hora ao longo de um pipe?

Provavelmente estou procurando uma maneira de armazenar em buffer um arquivo no início de um canal, o que, em contraste com isso:

    cat foo.txt | grep bar > foo.txt

... preservaria os dados de entrada da destruição pelo próprio canal. Existe tal buffer em estoque?

    
por Alex 24.06.2009 / 13:13

6 respostas

6

Eu acho que sed ainda pode criar o arquivo temporário, mas o seguinte pode fazer o que você quer? (O uso de strace pode mostrar se o sed cria um arquivo temporário ou não).

sed -i '/bar/!d' foo.txt

O ponto de exclamação inverte a correspondência, d é para deletar, então isso remove todas as linhas que não possuem barras.

    
por 24.06.2009 / 13:31
12

Tente usar a esponja de moreutils assim:

sed "s/root/toor/" /etc/passwd | grep -v joey | sponge /etc/passwd

Ele coleta toda a entrada antes de gravar na saída.

    
por 24.06.2009 / 13:41
1

Use > > para preservar o conteúdo.

cat foo.txt | grep bar >> foo.txt

Agora, isso será anexado ao arquivo.

AFAIK, não há maneira direta de acrescentar dados a um arquivo no shell. Se você quiser prefixar, pode ser necessário usar um arquivo temporário entre eles.

    
por 24.06.2009 / 13:31
0

Dependendo de quão complexa é a sua linha de comando, você pode obter milhagem de

cat foo.txt | grep bar | tee -a foo.txt
    
por 24.06.2009 / 13:41
0

A melhor maneira de fazer isso é lembrar como os arquivos funcionam no unix - o arquivo existe, desde que haja um link para o arquivo (diretório ou processo que abre o arquivo).

Portanto, abra o arquivo, exclua essa entrada de diretório e execute o processo que grava em uma nova entrada de diretório com o mesmo nome, mas vinculada a um inode diferente.

Por último, o bom disso é que ele funciona para qualquer tipo de operação de pipeline, não apenas para as coisas que podem fazer o hack do buffer de arquivo temporário.

{ rm file ; sed -e s/this/that/g > file ; } < file

Uma palavra de advertência - isso pode causar um desastre se você precisar que sua reescrita seja uma operação atômica. O unix não oferece maneiras limpas de bloquear arquivos, especialmente no nível do shell. Isso era um problema na idade das trevas se você estivesse fazendo algo como editar um arquivo de senha em um sistema ocupado que estava rodando algo como o NIS. Sempre que mais de um processo estiver lendo / gravando em um arquivo, tenha muito cuidado se o seu sistema estiver ocupado ou importante.

As únicas operações que são 100% certas de serem atômicas são as manipulações de entrada de diretório - rm / ln / mv (no mesmo sistema de arquivos).

Então agora as coisas ficam mais longas e feias ..

A parte de matemática disto requer uma concha posix ou concha bourne similarmente estendida

c=0
    while
      f=$SECONDS
      test -f file.$c.tmp
    do
      c=$(($c+1))
    done

  grep stuff < file > file.$c.tmp && mv file.$c.tmp file
    
por 24.06.2009 / 15:07
0

Ooops, UUOC, uso inútil de gato :) você não precisa de gato lá:

grep something somefile > someotherfile

Como se diz, há esponja. Ou talvez você queira experimentar a edição em linha perl (-i switch):

  • imprimir apenas a saída correspondente:

    perl -ni -e 'm/foo/g and print ' bar.txt

  • substitua "foo" por "bar" no arquivo:

    perl -pi -e 's/foo/bar/g' bar.txt

por 24.06.2009 / 16:26

Tags