Como a modificação no local de um arquivo está sendo feita?

10

O que a modificação "inplace" de um arquivo, por exemplo? via sed -i ou perl -i mean?
Minha pergunta é sobre como essa modificação inplace é feita. É o arquivo copiado a modificação é feita na cópia e depois substituir o original? Ou o arquivo original está de alguma forma sendo modificado?

    
por Jim 23.07.2014 / 09:48

2 respostas

18

sed cria um arquivo temporário, grava a saída nesse arquivo e, em seguida, renomeia o arquivo temporário na parte superior do original.

Você pode assistir ao que acontece usando strace :

$ strace -e trace=file sed -i -e '' a
execve("/usr/bin/sed", ["sed", "-i", "-e", "", "a"], [/* 34 vars */]) = 0
<...trimmed...>
open("a", O_RDONLY)                     = 3
open("./sedxvhRY8", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
rename("./sedxvhRY8", "a")              = 0
+++ exited with 0 +++

Isso registra todas as operações de arquivo sed makes: cria um novo arquivo (com segurança em O_CREAT|O_EXCL ), grava os dados nele e, em seguida, o move de volta para o início do arquivo original a . / p>

sed -i aceita um sufixo para usar como backup e, nesse caso, ele move o original para fora do caminho primeiro (em vez de renomear por cima). Esse argumento é obrigatório na maioria dos BSD sed s. Nesse caso, há um breve tempo em que não há nenhum arquivo com o nome certo no diretório.

perl nas versões recentes abre o arquivo de entrada, exclui e cria um novo arquivo com o mesmo nome:

open("a", O_RDONLY)               = 3
unlink("a")                       = 0
open("a", O_WRONLY|O_CREAT|O_EXCL, 0600) = 4

Quando você exclui ( unlink ) um arquivo que você já tem aberto, você mantém o acesso para ele, enquanto você mantiver a alça ao redor, para que ele possa continuar lendo os dados do arquivo excluído. Desta forma, perl escreve diretamente no arquivo de saída, em vez de em um arquivo temporário: nenhum arquivo adicional é criado, mas se você ler o arquivo durante o processo, obterá conteúdo parcial, diferente da abordagem de sed . Há também um breve momento em que não há nenhum arquivo com o nome certo, que está no início do processo, e não no final (como em sed -i .bak ).

Tanto sed como perl serão:

  • Substitua um link simbólico por um arquivo comum.
  • Quebre os links físicos.
  • Preserve a propriedade do grupo, se possível.
  • Crie o arquivo com seu grupo padrão (ou o grupo do diretório pai, se esse diretório tiver o setgid bit), se ele pertencesse a um grupo no qual você não está e você não é root.
  • Preserve a propriedade do arquivo se você for root.
  • Preserve permissões básicas.
  • Preserve setuid e setgrp bits, se o grupo resultante for o mesmo do grupo em que começou.
  • Preserve o bit adesivo.
  • Não preserva xattrs.

sed :

  • Preservar ACLs (No Linux, não sei sobre os outros)

perl :

  • Não preserva as ACLs.

O acima é verdadeiro no Linux com o GNU sed e o Mac OS X com o seu (derivado do FreeBSD) sed .

    
por 23.07.2014 / 09:55
3

Em adicional a @ resposta de Homer, de perldoc perlrun :

specifies that files processed by the "<>" construct are to be edited in-place. 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, following these rules:

If no extension is supplied, no backup is made and the current file is overwritten.

If the extension doesn't contain a *, then it is appended to the end of the current filename as a suffix. If the extension does contain one or more * characters, then each * is replaced with the current filename.

E lembre-se de que nenhum link ou link físico é preservado:

Note that because -i renames or deletes the original file before creating a new file of the same name, UNIX-style soft and hard links will not be preserved.

Finally, the -i switch does not impede execution when no files are given on the command line. In this case, no backup is made (the original file cannot, of course, be determined) and processing proceeds from STDIN to STDOUT as might be expected.

Isso também explica por que você deve usar a opção -i with -p ou usar uma instrução explícita print se quiser editar no local com perl :

# Opps, file will be truncated, becomes empty
$ perl -i.bak -ne 's/123/qwe/' file

# Right way
$ perl -i.bak -ne 's/123/qwe/;print' file

# Or
$ perl -i.bak -pe 's/123/qwe/' file
    
por 23.07.2014 / 11:18

Tags