Um amigo meu ressalta que, se você fizer:
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 fará:
Isso é feito renomeando o arquivo de entrada, abrindo o arquivo de saída pelo nome original e selecionando esse arquivo de saída como o padrão para instruções print (). A extensão, se fornecida, é usada para modificar o nome do arquivo antigo e fazer uma cópia de backup.
O que resulta em um novo link simbólico "somefile.bak" apontando para o arquivo real inalterado e um novo arquivo regular alterado "somefile" com as alterações.
Em muitos casos, seguir o link simbólico 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 adequadamente?
( sed
faz a mesma coisa, pelo que vale a pena.)
-p -i
em seu script.Respostas:
Gostaria de saber se o pequeno
sponge
utilitário de uso geral ("absorver entrada padrão e gravar em um arquivo") do moreutils será útil nesse caso e se seguirá o link simbólico.O autor descreve
sponge
assim:fonte
sponge
esse uso na prática? Quanto a mim: ainda não. Você poderia deixar um comentário informando se ele se comportou em um teste da maneira desejada aqui? Oh, eu vejo o comentário. Obrigado pela confirmação!file
no exemplo acima, houver um link simbólico, o link será deixado sozinho e o arquivo real será alterado.Se você sabe que
somefile
é um link simbólico, é possível fornecer explicitamente o caminho completo do 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.
fonte
readlink
ainda pode ser outro link simbólico. O melhor seria usar-f
ou,-e
quando disponívelzsh
,$file:P
ou(:P)
qualificador glob ou, como mostrado pelo @ikegami, para obter um caminho sem links .Se você estiver lidando com um único arquivo, o comando terá a seguinte aparência:
A solução é a seguinte:
Isso lida com links simbólicos e não simbólicos.
Se você estiver lidando com um número arbitrariamente grande de arquivos, o comando terá a seguinte aparência:
A solução é a seguinte:
Isso lida com links simbólicos e não simbólicos.
A 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 possuem-f
(que você também pode usar aqui), mas não-e
, outras também.busybox
éreadlink -f
se comporta como GNUreadlink -e
. E alguns sistemas têm umrealpath
comando em vez doreadlink
qual geralmente se comporta como o GNUreadlink -f
.Cuidado com o GNU
readlink -e
, links simbólicos que não podem ser resolvidos para um arquivo existente são removidos silenciosamente.fonte
$var:P
não funciona para mim. (X='tmp' zsh -c 'perl -E"say for @ARGV" $X:P'
saídastmp:P
)$var:P
. Nas versões mais antigas, você sempre pode usar$var:A
. Consulte o manual para as diferenças e zsh.org/mla/users/2016/msg00593.html para justificativa da introdução:P
(arealpath()
interface real ).:A
foi adicionado em 4.3.10 (2009), GNUreadlink -z
em 2012, não conheço nenhuma outrareadlink
implementação que suporte-z
). Observe que, com o GNUxargs
, você geralmente deseja a-r
opção, a menos que possa garantir que a entrada não fique vazia. Aqui, não é grande coisa (a menos que operl
código contenha uma declaraçãoBEGIN
/END
), você receberá um-i used with no filenames on the command line, reading from STDIN.
aviso se isso acontecer.-r
a documentação. Eu pensei que fiz o oposto do que faz. Readded.