Existe uma maneira de fazer perl -i não estrobiar links simbólicos?

11

Um amigo meu diz que, se você fizer isso:

perl -pi.bak -e 's/foo/bar/' somefile

quando "somefile" é na verdade um link simbólico, o perl faz exatamente o que os documentos dizem que ele fará:

It does this by renaming the input file, opening the output file by the original name, and selecting that output file as the default for print() statements. The extension, if supplied, is used to modify the name of the old file to make a backup copy [...]

O que resulta em um novo symlink "somefile.bak" apontando para o arquivo real inalterado, e um novo arquivo regular "somefile" alterado com as mudanças.

Em muitos casos, seguir o symlink seria o comportamento desejado (mesmo que ele deixe o local correto do arquivo .bak ambíguo). Existe uma maneira simples de fazer isso além de testar links simbólicos em um wrapper e manipular o caso apropriadamente?

( sed faz a mesma coisa, pelo que vale a pena)

    
por mattdm 15.03.2011 / 21:53

3 respostas

5

Gostaria de saber se o pequeno sponge utilitário de uso geral ("absorva a entrada padrão e escreva para um file ") de moreutils será útil neste caso e se seguirá o symlink.

O autor descreve sponge like this :

It addresses the problem of editing files in-place with Unix tools, namely that if you just redirect output to the file you're trying to edit then the redirection takes effect (clobbering the contents of the file) before the first command in the pipeline gets round to reading from the file. Switches like sed -i and perl -i work around this, but not every command you might want to use in a pipeline has such an option, and you can't use that approach with multiple-command pipelines anyway.

I normally use sponge a bit like this:

sed '...' file | grep '...' | sponge file
    
por 16.03.2011 / 01:05
3

Se você sabe que somefile é um link simbólico, você pode fornecer explicitamente o caminho completo para o arquivo com o seguinte:

perl -pi.bak -e 's/foo/bar/' $(readlink somefile)

Dessa forma, o link simbólico original permanece intacto, pois a substituição agora é feita diretamente com o arquivo original.

    
por 23.10.2015 / 18:33
1

Se você estiver lidando com um único arquivo, o comando será o seguinte:

perl -i -pe'...' -- "$qfn"

A solução então é a seguinte:

perl -i -pe'...' -- "$( readlink -e -- "$qfn" )"

Isso lida com links simbólicos e sem links simbólicos.

Se você está lidando com um número arbitrariamente grande de arquivos, o comando ficaria assim:

... | xargs -r perl -i -pe'...' --

A solução então é a seguinte:

... | xargs -r readlink -ze -- | xargs -r0 perl -i -pe'...' --

Isso lida com links simbólicos e sem links simbólicos.

Advertência readlink não é um comando padrão, portanto, sua presença, seus argumentos e sua funcionalidade variam de acordo com o sistema, portanto, verifique sua documentação. Por exemplo, algumas implementações têm -f (que você também pode usar aqui), mas não -e , outras nem. busybox readlink -f se comporta como GNU readlink -e . E alguns sistemas têm um comando realpath em vez de readlink , que geralmente se comporta como o GNU readlink -f .

Cuidado com o GNU readlink -e , links simbólicos que não podem ser resolvidos para um arquivo existente são removidos silenciosamente.

    
por 04.11.2018 / 09:24