Por que você não escreve apenas
sed -i -e 's/a/a/g' messages.txt
o -i significa "no lugar"
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
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 .
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
Você pode usar o Vim no modo Ex:
ex -sc '%s/OLD/NEW/g|x' messages.txt
%
seleciona todas as linhas
s
substituto
g
global replace
x
salvar e fechar