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

10

O que significa a modificação "local" de um arquivo, por exemplo, via sed -iou perl -isignifica?
Minha pergunta é sobre como é feita essa modificação no local. O arquivo foi copiado, a modificação é feita na cópia e substituída pelo original? Ou o arquivo original está sendo modificado de alguma maneira?

Jim
fonte
Ter um olhar para backreference.org/2011/01/29/in-place-editing-of-files para uma explicação detalhada deste tópico.
Scy
Para esse assunto, como é feito com exou vi?
Curinga
@Wildcard - cada um deles possui um sistema completo. exmantém um arquivo de mensagens (como, dead.mailou algo em ~ você, e outro em algum lugar próximo ao seu spooler de mensagens, geralmente) . verifique as especificações - cada uma delas possui um estado definido para grandes comprimentos ... extem seu próprio formato binário na maioria dos casos (veja o seu -rescuearquivo) e isso é usado para pré-zerar arquivos buffer temporários separados (possivelmente até seis) . Então, esses blocos de entrada são copiados para editar buffers e gravações sincronizadas em offsets por alterações :!written?
mikeserv

Respostas:

18

sed cria um arquivo temporário, grava a saída nesse arquivo e renomeia o arquivo temporário por cima 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 sedefetuadas: cria um novo arquivo (com segurança O_CREAT|O_EXCL), grava os dados nele e depois move-os de volta ao topo do meu arquivo original a.

sed -iaceita um sufixo para usar como backup e, nesse caso, move o original primeiro (em vez de renomear por cima). Esse argumento é obrigatório na maioria dos BSDs sed. Nesse caso, há um breve momento em que não há nenhum arquivo com o nome correto no diretório.

perl nas versões recentes abre o arquivo de entrada, exclui-o 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á abriu, você mantém o acesso a ele enquanto mantiver o controle, para que ele continue lendo os dados do arquivo excluído. Dessa maneira, perlgrava 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, ao contrário sedda abordagem. Também há um breve momento em que não há arquivo com o nome correto, que está no início do processo e não no final (como em sed -i .bak).


Ambos sede perlirão:

  • Substitua um link simbólico por um arquivo comum.
  • Quebrar links físicos.
  • Preserve a propriedade do grupo, se possível.
  • Crie o arquivo com o seu grupo padrão (ou o grupo do diretório pai, se esse diretório tiver o setgidbit), se pertencesse a um grupo em que você não pertence e não é root.
  • Preserve a propriedade do arquivo se você for root.
  • Preservar permissões básicas.
  • Preservar setuide setgrpbits, se o grupo resultante for o mesmo que o grupo em que foi iniciado.
  • Preserve a parte pegajosa.
  • Não preserve xattrs.

sed vai:

  • Preservar ACLs (no Linux; não conheço outras pessoas) .

perl vai:

  • Não preservar ACLs.

O acima é verdade no Linux com GNU sede Mac OS X (derivado do FreeBSD) sed.

Michael Homer
fonte
3

Além da resposta de @ Homer, de perldoc perlrun:

especifica que os arquivos processados ​​pela construção "<>" devem ser editados no local. Isso é feito renomeando o arquivo de entrada, abrindo o arquivo de saída com o 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 para fazer uma cópia de backup, seguindo estas regras:

Se nenhuma extensão for fornecida, nenhum backup será feito e o arquivo atual será substituído.

Se a extensão não contiver um *, ela será anexada ao final do nome do arquivo atual como sufixo. Se a extensão contiver um ou mais * caracteres, cada * será substituído pelo nome do arquivo atual.

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

Observe que, como -i renomeia ou exclui o arquivo original antes de criar um novo arquivo com o mesmo nome, os links físicos e físicos no estilo UNIX não serão preservados.

Finalmente, a opção -i não impede a execução quando nenhum arquivo é fornecido na linha de comandos. Nesse caso, nenhum backup é feito (o arquivo original não pode, é claro, ser determinado) e o processamento prossegue de STDIN para STDOUT conforme o esperado.

Isso também explica por que você deve usar -icom a -popção ou usar uma printinstrução explícita se desejar 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
cuonglm
fonte