Lê um arquivo e copia para outro arquivo

3

Estou tendo um problema, preciso copiar o conteúdo do arquivo e remover algumas linhas se elas corresponderem à saída de um comando anterior. Mas até agora, estou tendo um problema em manter as linhas de arquivo exatamente iguais. Eu estou colocando a parte simples do script como o if para omitir a cópia não fazem parte do problema, pois isso acontece com linhas não afetadas.

Para o exemplo:

No arquivo original eu tenho o seguinte

Testing,      resuming text

Quando executar o script, os campos se tornam:

Testing, resuming text

Estou fazendo o seguinte:

#!/usr/bin/bash
rm /tmp/dest_file
while read line
do
   echo $line >> /tmp/dest_file
done < $1

O problema que tenho com isso é que os arquivos se tornarão diferentes devido aos campos formatados da guia.

    
por BitsOfNix 20.12.2012 / 13:41

2 respostas

3

Cite sua variável:

echo "$line" >> /tmp/dest_file
    
por 20.12.2012 / 13:43
6

Isso já foi feito várias vezes neste site - consulte Noções básicas sobre o IFS e as perguntas vinculadas. Nesta resposta, vou resumir o que pode dar errado e como evitá-lo; veja os tópicos ligados para detalhes.

read line realiza as seguintes ações:

  1. Leia da entrada padrão até o primeiro byte que é uma nova linha ou nulo e coloque os dados na variável chamada line .
  2. Retire qualquer barra invertida que não esteja no final da linha. Uma barra invertida dupla \ se torna uma única barra invertida. Em outras palavras, a barra invertida cita o próximo caractere, desde que não seja uma nova linha.
  3. Se read parar em uma nova linha e o caractere no final da linha for um \ , remova a sequência da nova linha invertida e continue lendo, anexando à variável line . Repita até o primeiro: uma nova linha que não seja precedida por uma barra invertida; um byte nulo; o final da entrada.
  4. Desmarque o sufixo mais longo de line que é feito de caracteres em $IFS . Por padrão, IFS contém uma guia, um espaço e uma nova linha, portanto, isso separa os espaços em branco ASCII do final do valor de line .
  5. Tira o prefixo mais longo de line que é feito de caracteres de espaço em branco em $IFS .

Por exemplo, se a entrada for

 : hello\
world: :
wibble

, em seguida, read line resulta em line contendo : helloworld: : (sem espaço inicial) com o valor padrão de IFS . Se IFS tiver sido alterado para : (apenas dois pontos), então read line resultará em  : helloworld:  (com um espaço no início e no final). Se IFS contiver : e um espaço, o resultado será : helloworld (sem espaço inicial ou final).

Para evitar a influência de IFS , defina-o como um valor vazio (observe que isso é diferente de desativá-lo). Você pode configurá-lo apenas para o comando read escrevendo IFS= read (consulte Por que é 'enquanto IFS = read' é usado com tanta frequência, ao invés de 'IFS =; while read ..'? ).

Para evitar o processamento de contrabarra, passe a opção -r para read .

A menos que o shell seja zsh, se houver um byte nulo na entrada, os caracteres subseqüentes serão perdidos. Os shells não são projetados para ler dados binários.

Assim, o idioma para ler uma linha por vez é:

while IFS= read -r line; do
  … # process "$line"
end

Quando você usa a variável line , certifique-se de que sempre coloque aspas duplas em torno das substituições de variáveis : "$line" . Sem aspas duplas, o shell primeiro expande o valor da variável e, em seguida, divide esse valor em palavras separadas, sempre que contiver caracteres de IFS , e cada palavra é interpretada como um padrão curinga e substituída pela lista de arquivos correspondentes (se não há arquivos correspondentes, o padrão é deixado como está). Portanto, echo 'a* b*' | IFS= read -r line; echo $line expande para a lista de arquivos no diretório atual, começando com a ou b ; para obter a entrada inalterada, use echo 'a* b*' | IFS= read -r line; echo "$line" .

Observe também que o comando echo às vezes modifica a sequência impressa. O caminho exato depende do shell. Alguns shells processam escapes de barra invertida e alguns shells reconhecem as opções. Usar echo para gerar uma string textual só funciona, você sabe que a string não contém nenhuma barra invertida e não inicia com um traço ( - ). Uma maneira confiável e portátil de imprimir uma string é

printf '%s\n' "$line"

Isso imprime uma nova linha após a string, como echo . Você pode omitir a nova linha omitindo \n no comando acima.

    
por 21.12.2012 / 01:53