Por que o sed age de maneira diferente dependendo do arquivo de saída?

5

Se eu correr:

cat messages.txt | sed -e 's/a/a/g' > messages.txt

em um arquivo grande (2500 + linhas) eu acho que o arquivo resultante terá apenas cerca de 900 linhas após o comando no cygwin e não terá linhas no gentoo. No entanto, se eu correr

cat messages.txt | sed -e 's/a/a/g' > other_messages.txt

retém todas as linhas como deveria.

Minha pergunta é por que e existe alguma maneira de fazer isso além de

cat messages.txt | sed -e 's/a/a/g' > other_messages.txt
rm messages.txt
mv other_messages.txt messages.txt
    
por ashleysmithgpu 05.10.2010 / 13:48

4 respostas

10

Por que você não escreve apenas

sed -i -e 's/a/a/g' messages.txt

o -i significa "no lugar"

    
por 05.10.2010 / 13:53
11

resposta do fschmitt é o melhor quando se usa sed; no entanto, em um sentido mais geral, esse antipadrão:

cat infile | filter > infile
É provável que

cause um bom número de problemas. Por exemplo, se eu tiver um arquivo chamado infile que se parece com isso:

Hello
World

e execute este comando:

cat infile | tr "[:upper:]" "[:lower:]"

Eu obtenho

hello
world

Mas se eu executar cat infile | tr "[:upper:]" "[:lower:]" > infile , receberei um arquivo vazio. Por quê?

Bem, quando você usa o operador de redirecionamento de saída > você está dizendo "Coloque minha saída padrão neste arquivo, e se esse arquivo existir, sobrescreva-o." Agora você pode pensar que isso deve funcionar, pois o filtro retornará todas as linhas do arquivo original. No entanto, o que muitas vezes acaba acontecendo é que o shell irá chocar seu arquivo antes que qualquer linha seja lida. Em seguida, seu comando de filtro irá ler as linhas de um arquivo vazio, não encontrar nenhum e, portanto, não retornar nenhum. Em alguns lugares, você pode ter "sorte" o suficiente para ter algumas linhas lidas antes que o arquivo fique danificado, mas é melhor simplesmente evitar esse padrão.

Para contornar esse problema específico, você tem algumas opções. Uma é simplesmente fazer algo como:

cat infile | filter > tmpfile; mv tmpfile infile

Se você precisa ter certeza de que seu arquivo temporário não vai chocar algum outro arquivo ou se outras coisas desagradáveis acontecerem com ele, você deve procurar em mktemp . (veja man mktemp e info coreutils mktemp )

Outra opção é usar sponge de moreutils .

Além disso, muitos desses exemplos são exemplos de usos inúteis do gato .

    
por 05.10.2010 / 17:41
2

No entanto, outra maneira (portátil) de editar um arquivo no local é usar ed .

# cf. http://wiki.bash-hackers.org/howto/edit-ed
cat <<-'EOF' | ed -s messages.txt
H
,g/a/s//b/g
wq
EOF


# ... or read the file contents into a variable, modify it and write it back to file
file_contents="$(cat messages.txt)"
printf '%s' "$file_contents" | sed -e 's/a/b/g' > messages.txt


# ... and, if you want to play around with a file descriptor hack, ...
# (As long as there's a fd associated with a file, the file can be accessed via the fd.) 

exec 3<messages.txt  # open file on fd 3 for reading
rm -f messages.txt
sed -e 's/a/b/g' <&3 > messages.txt
    
por 10.11.2011 / 15:23
0

Você pode usar o Vim no modo Ex:

ex -sc '%s/OLD/NEW/g|x' messages.txt
  1. % seleciona todas as linhas

  2. s substituto

  3. g global replace

  4. x salvar e fechar

por 17.04.2016 / 04:37

Tags