Como evito que o sed destrua os hardinks?

3

A minha pergunta é semelhante a Como evito sed - Eu estou destruindo links simbólicos? , mas sobre hardlinks.

Usar sed -i para trabalhar em um arquivo destrói todos os hardlinks que o arquivo possui, já que o sed funciona gravando em um arquivo temporário e, em seguida, movendo isso. O parâmetro --follow-symlinks não ajuda no caso de um link físico.

Existe uma alternativa para usar o bastante feio:

sed 's/cat/dog/' pet_link > pet_link
    
por user186430 25.08.2016 / 12:29

4 respostas

12

Para sed 's/cat/dog/' ou qualquer outra substituição que não altere o tamanho do arquivo, com qualquer shell parecido com o Bourne, você pode fazer:

sed 's/cat/dog/' < file 1<> file

O pouco conhecido, mas com mais de 35 anos de idade¹ padrão <> operator é para abrir um arquivo no modo de leitura + gravação sem truncamento . Basicamente, aqui isso faz com que sed escreva sua saída sobre sua entrada. É importante garantir que a saída não sobrescreva as seções do arquivo que sed ainda não leu.

Para substituições que diminuem o tamanho do arquivo, com ksh93 :

sed 's/hippopotamus/ant/' < file 1<>; file

<>; , uma extensão ksh93 é igual a <> , exceto que, se o comando que está sendo redirecionado for bem-sucedido, o arquivo será truncado quando o comando terminar.

Ou com o perl:

perl -pe 's/hippopotamus/ant/;
          END{truncate STDOUT, tell STDOUT}' < file 1<> file

Para qualquer outra coisa, basta usar o formulário padrão:

cp -i file file.back &&
  sed 's/dog/horse/g' < file.back > file # && rm -f file.back

¹ Embora a implementação inicial no shell Bourne e nas versões iniciais do shell Korn estivesse realmente quebrada, corrigida no final dos anos 80. E a concha de Almquist inicialmente não a apoiava.

    
por 25.08.2016 / 12:39
2

Observe que sed é um editor de S tream ED itor, não de arquivo , portanto, as pessoas tendem a abusar dele por tentar para editar arquivos. Basicamente, a opção -i é extensões não padronizadas do FreeBSD (podem não estar disponíveis em outros sistemas operacionais), em segundo lugar não edita arquivos - faz uma cópia e substitui o arquivo original pela cópia. BashFAQ

A alternativa é usar o ed ou o comando ex (parte do Vim) que tem sintaxe semelhante, por exemplo,

ex +%s/cat/dog/e -scwq pet_link

Ou de acordo com @Wildcard recomendação:

printf '%s\n' '%s/cat/dog/' x | ex pet_link

Para vários arquivos, você pode usar:

ex "+bufdo! %s/foo/bar/ge" -scxa **/*.lnk

Se o seu shell suportar uma nova opção de globbing (habilitar por: shopt -s globstar ), usando ** neste caso, funcionará recursivamente.

Para obter mais sintaxe POSIX , você pode tentar (de acordo com sugestão @Wildcard ):

for f in *.txt; do printf '%s\n' '%s/cat/dog/g' x | ex "$f"; done

ou:

find . -type f -exec sh -c 'for f; do printf "%s\n" "%s/cat/dog/g" x | ex "$f"; done' sh {} +

Relacionados:

por 31.01.2017 / 23:13
0

Um pouco de ed :

$ ed pet_link <<END_OF_ED
g/cat/s//dog/
w
END_OF_ED

Isso não quebra o link físico.

    
por 31.01.2017 / 23:50
0

Acho que isso funciona bem (preservando links simbólicos e hard links):

sed 's/cat/dog/' pet_link > pet_link.tmp
cat pet_link.tmp > pet_link
rm pet_link.tmp
    
por 27.11.2017 / 01:43

Tags