É possível modificar um arquivo em um diretório somente leitura? [duplicado]

4

Eu já li: Existe uma maneira de modificar um arquivo no local? Estou curioso para saber se existe uma maneira de modificar um arquivo usando um comando que não criará arquivos temporários. Digamos que eu crie um diretório %código% e então eu crio alguns arquivos dentro de read_only. Quando eu estou feliz em criar arquivos, eu corro mkdir read_only . É possível modificar qualquer um dos arquivos agora sem o uso de um arquivo temporário? Especificamente, gostaria de uma solução que pudesse ser feita a partir de um script bash. Eu não quero saber se é possível; Eu também estou procurando uma solução. Todas as idéias que tenho gerenciado até agora com comandos bash / unix criam arquivos temporários.

Edit: Acredito que minha pergunta não é uma duplicata de Um arquivo pode ser editado com a permissão 'write', mas não em seu diretório pai? pelas seguintes razões:

  • Estou procurando uma solução além de perguntar "can". Considerando que, eles só pediram "pode".
  • As respostas sobre o possível duplicado não respondem totalmente à minha pergunta. Eu peço comandos que podem ir em um script bash.
por Kevin Tindall 13.04.2015 / 00:39

4 respostas

10

Você precisa da permissão de gravação em um diretório para criar ou remover arquivos, mas não para gravar em um arquivo. A maioria dos comandos shell, quando recebe um arquivo de saída, simplesmente abre esse arquivo para gravação e substitui os dados que estavam anteriormente no arquivo. O operador de redirecionamento > trunca o arquivo existente (isto é, exclui o conteúdo do arquivo existente, resultando em um arquivo com tamanho zero) e começa a gravar nele. O operador de redirecionamento >> faz com que os dados sejam anexados ao final do arquivo.

Escrever em arquivos é limitado pelas possibilidades oferecidas pela interface de baixo nível. Você pode sobrescrever bytes em um arquivo no lugar, anexar ao final do arquivo e truncar um arquivo para um tamanho escolhido. Não é possível inserir bytes ao alternar bytes subseqüentes (como em foobarfooNEWSTUFFbar ) nem excluir bytes enquanto alterna bytes subseqüentes para trás (como em foobarfor ), exceto simulando essas operações lendo os dados para mover e escrever no seu novo local.

O problema com a edição de arquivos é que é difícil garantir que o conteúdo do arquivo permaneça consistente se algo der errado (bug do programa, disco cheio, perda de energia,…). É por isso que o processamento robusto de arquivos geralmente envolve a gravação de um arquivo temporário com os novos dados e a movimentação do arquivo temporário.

Outra limitação na edição de arquivos é que operações complexas envolvendo leituras e gravações não são atômicas. Este é um problema apenas se alguma outra tarefa desejar ler o arquivo ao mesmo tempo que sua modificação. Por exemplo, se você alterar foobar para fooNEWSTUFFbar lendo os últimos 3 bytes ( bar ), em seguida, gravando os novos dados ( foofooNEWSTUFF ) e, finalmente, anexando a cauda antiga ( fooNEWSTUFFfooNEWSTUFFbar ), um leitor concorrente pode ver fooNEWSTUFF ou até mesmo outros estados parciais do arquivo com apenas parte dos dados gravados. Novamente, gravar em um arquivo temporário primeiro resolve esse problema, porque mover o arquivo temporário no lugar é uma operação atômica.

Se você não se importa com essas limitações, pode modificar um arquivo no lugar. Anexar dados é fácil ( >> ), a maioria das outras transformações estão mais envolvidas. Uma armadilha comum é que

somefilter <somefile >somefile

NÃO aplica somefilter ao conteúdo do arquivo: o operador > trunca o arquivo de saída antes de somefilter começar a ler a partir dele.

moreutils de Joey Hess contém um utilitário chamado sponge que corrige este problema. Em vez de redirecionar a saída para somefile , você canaliza para sponge , que lê todas as suas entradas e então substitui o arquivo existente pela entrada que foi lida. Observe que ainda é possível acabar com dados parciais se o filtro falhar.

somefilter <somefile | sponge somefile

Se você não tiver sponge , a maneira fácil e portátil de corrigir isso é primeiro ler os dados na memória:

content=$(cat somefile; echo a)
content=${content%a}

O echo a bit é para preservar as novas linhas no final do arquivo - a substituição de comandos sempre remove as novas linhas. Você pode então passar o conteúdo para um comando:

printf %s "$content" | somefilter >somefile

Isso substitui o conteúdo do arquivo pela saída do filtro. Se o comando falhar por algum motivo, o conteúdo original do arquivo é perdido e o arquivo contém os dados que o comando escreveu antes de falhar.

Tenha em atenção que este método não funciona para ficheiros binários, porque a maioria das shells não suporta bytes nulos.

Outra maneira de modificar um arquivo é usar o editor ed , que tem uma strong semelhança com sed , mas carrega o arquivo na memória e o salva no lugar, ao contrário da operação linha por linha do sed.

Atuar em um arquivo sem carregá-lo na memória e sem criar um arquivo temporário é mais complicado apenas com ferramentas shell padrão, mas isso pode ser feito. O redirecionamento de shell e a maioria dos utilitários de processamento de texto permitem que você acrescente a um arquivo ou sobrescreva-o desde o início. Você pode usar dd conv=notrunc seek=… para sobrescrever dados em algum deslocamento em um arquivo sem afetar as partes que não estão sendo sobrescritas; veja Existe uma maneira de modificar um arquivo no local? para um exemplo.

    
por 13.04.2015 / 02:00
3

Se o diretório for somente leitura, mas os arquivos dentro desse diretório forem de leitura / gravação, não haverá nada que o impeça de sobrescrever esses arquivos.

De um script, você pode gravar nos arquivos usando o redirecionamento normal > e >> , além de sobrescrevê-los usando cp .

O que você não pode fazer é criar um novo arquivo no diretório e renomeá-lo sobre um arquivo existente. Criar um novo arquivo e renomeá-lo é muitas vezes desejável devido à renomeação acontecer atomicamente. Isso fornece alguma proteção contra a perda de dados e impede que qualquer outro processo que leia o arquivo por meio do nome comum veja apenas um arquivo parcial durante as atualizações.

A falta da capacidade de criar um novo arquivo e renomear o topo significa que você deve pensar com muito cuidado sobre as garantias necessárias ao atualizar os arquivos.

    
por 13.04.2015 / 00:57
3

O % móduloTie::File do Perl oferece a verdadeira funcionalidade de edição in-loco:

perl -MTie::File -e '
    tie @a,"Tie::File","your_file_here";
    # Do something...
'

Isso torna os elementos de @a nas linhas de seu arquivo e quaisquer alterações feitas em @a são refletidas no arquivo, mesmo se o arquivo estiver em um diretório somente leitura.

    
por 13.04.2015 / 01:07
1

Não. Não é possível usar a opção -i do sed ou perl para editar arquivos em um diretório somente leitura. Como você supôs corretamente, não será permitido criar os arquivos temporários necessários:

$ ls -ld read_only/
dr-xr-xr-x 2 terdon terdon 4096 Apr 13 02:16 read_only/
$ ls -l read_only/file 
-rw-r--r-- 1 terdon terdon 3 Apr 13 02:16 read_only/file
$ sed -i 's/a/A/' read_only/file
sed: couldn't open temporary file read_only/sedOEdv8L: Permission denied
$ perl -i -pe 's/a/A/' read_only/file
Can't remove read_only/file: Permission denied, skipping file.

Você pode, no entanto, usar o fantástico truque Perl do Joseph.R:

$ perl -MTie::File -e 'tie @a,"Tie::File","$ARGV[0]"; $a[0]=~s/a/A/' read_only/file  
    
por 13.04.2015 / 01:20