
Tenho um requisito em meu projeto para substituir algum texto existente em um arquivo comofoo
com algum outro texto comofooofoo
:
abc.txt
name
foo
foo1
Então eu tentei:
sed -i "s/foo/fooofoo/g" abc.txt
No entanto, recebo este erro:
sed: opção ilegal --
i
Encontrei no manual que devo usar:
sed -i\ "s/foo/fooofoo/g" abc.txt
No entanto, isso também não está funcionando.
Encontrei alternativas em perl
e awk
também, mas uma solução no Solaris sed
seria muito apreciada.
Estou usando esta versão do bash:
GNU bash, versão 3.2.57(1)-lançamento (sparc-sun-solaris2.10)
Responder1
Usared
. Está disponível na maioria das plataformas e pode editar seus arquivos no local.
Como sed
se baseia na ed
sintaxe para substituição de padrões é semelhante:
ed -s infile <<\IN
,s/old/new/g
w
q
IN
Responder2
Se você não conseguir instalar o GNU sed, use:
sed "s/foo/fooofoo/g" abc.txt >abc.tmp && mv abc.tmp abc.txt
Isso usaredirecionamentopara enviar a saída do sed para um arquivo temporário. Se o sed for concluído com êxito, ele será substituído abc.txt
pelo arquivo temporário.
Como pode ser visto no código fonte do GNU sed, é exatamente isso que sed -i
acontece. Então, isso é tão eficiente quanto sed -i
.
Se já existir uma chance abc.tmp
, você pode querer usar mktemp
ou um utilitário semelhante para gerar o nome exclusivo para o temporário.
Responder3
Se você quiser o equivalente a sed -i.bak
, é bem simples.
Considere este script para GNU sed:
#!/bin/sh
# Create an input file to demonstrate
trap 'rm -r "$dir"' EXIT
dir=$(mktemp -d)
grep -v '[[:upper:][:punct:]]' /usr/share/dict/words | head >"$dir/foo"
# sed program - removes 'aardvark' and 'aardvarks'
script='/aard/d'
##########
# What we want to do
sed -i.bak -e "$script" "$dir"
##########
# Prove that it worked
ls "$dir"
cat "$dir/foo"
Podemos simplesmente substituir a linha marcada por
cp "$dir/foo" "$dir/foo.bak" && sed -e "$script" "$dir/foo.bak" >"$dir/foo"
Isso move o arquivo existente para um backup e grava um novo arquivo.
Se quisermos o equivalente a
sed -i -e "$script" "$dir" # no backup
então é um pouco mais complexo. Podemos abrir o arquivo para leitura como entrada padrão e desvinculá-lo antes de direcionar a saída do sed para substituí-lo:
( cp "$dir/foo" "$dir/foo.bak"; exec <"$dir/foo.bak"; rm "$dir/foo.bak"; exec sed -e "$script" >"$dir/foo" )
Fazemos isso em um sub-shell, para que nosso stdin original ainda esteja disponível depois disso. É possível alternar entradas e voltar sem um subshell, mas dessa forma parece mais claro para mim.
Observe que temos o cuidado de copiar primeiro, em vez de criar um novo foo
arquivo - isso é importante se o arquivo for conhecido por mais de um nome (ou seja, tiver links físicos) e você quiser ter certeza de não quebrar os links .
Responder4
Usando sed
e nãovisívelArquivo temporário:
Você pode evitar criar um separadovisível"arquivo temporário":
exec 3<abc.txt
rm abc.txt
sed 's/foo/fooofoo/' <&3 >abc.txt
exec 3<&-
Explicação
Os sistemas do tipo Unix não removem o conteúdo do arquivo do disco até que ele sejaambosdesvinculado no sistema de arquivos,enão aberto em nenhum processo. Portanto, você pode exec 3<
abrir o arquivo no shell para leitura no descritor de arquivo 3, rm
o arquivo (que o desvincula do sistema de arquivos) e, em seguida, chamar sed
com o descritor de arquivo 3 usado como entrada.
Observe que isso émuitodiferente disso:
# Does not work.
sed 's/foo/fooofoo/' <abc.txt >abc.txt
A diferença é que quando você faz isso em um comando, o shell apenas abre o mesmo arquivo tanto para leitura quanto para escrita com a opção de truncar o arquivo - como ainda é o mesmo arquivo, você perde o conteúdo. Mas se você abri-lo para leitura, então rm
abrir o mesmo nome de caminho para gravação, você está na verdade criando um novo arquivo com o mesmo nome de caminho (mas em um novo inode e local de disco, já que o original ainda está aberto): então o conteúdo ainda está disponível.
Então, quando terminar, você pode fechar o descritor de arquivo aberto anteriormente (é isso que a exec 3<&-
sintaxe especial faz), que libera o arquivo original para que o sistema operacional possa excluir (marcar como não utilizado) seu espaço em disco.
Ressalvas
Há algumas coisas que você deve ter em mente sobre esta solução:
Você só pode "examinar" o conteúdo uma vez - não háportátilmaneira de um shell "procurar" de volta no descritor de arquivo - assim, quando um programa lê parte do conteúdo, outros programas verão apenas o restante do arquivo. E
sed
lerá o arquivo inteiro.Há uma pequena chance de seu arquivo original ser perdido se seu shell/script/sed for eliminado antes de terminar.