A classificação suporta a classificação de um arquivo no local, como `sed - in-place`?

80

Sou cego ou não existe uma opção --in-placepara isso sort?

Para salvar os resultados no arquivo de entrada, sed usa -i( --in-place).

Redirecionando a saída sortpara o arquivo de entrada

sort < f > f

resulta em torná-lo vazio. Se não houver --in-placeopção - talvez haja algum truque para fazer isso de maneira prática ?

(A única coisa que me vem à cabeça:

sort < f > /tmp/f$$ ; cat /tmp/f$$ > f ; rm /tmp/f$$

Mover não é a escolha certa, pois as permissões do arquivo podem ser alteradas. É por isso que sobrescrevo o conteúdo do arquivo temporário que removo.)

Grzegorz Wierzowiecki
fonte
Também existe insitu, permitindo que qualquer comando seja usado no local.
sr_
@sr_, esse é um comando interessante, mas não funciona com nenhum comando, apenas aqueles que escrevem não mais rápido do que lêem (caso contrário, ele estraga o arquivo de entrada antes que o comando o leia). Não há garantia de que funcione sort.
Cjm
@ CCJ, eu realmente não tenho certeza, mas isso não deveria lidar com esse caso?
sr_
@sr_, acho que você está certo. Eu li a descrição em vez de olhar para a fonte. Embora para arquivos realmente grandes, ele pode ficar sem memória para o buffer e travar (não parece que ele procura um retorno NULL do malloc).
Cjm
@ cjm: Ah, sim, de fato.
sr_

Respostas:

110

sorttem a -o, --outputopção que aceita um nome de arquivo como argumento. Se for o mesmo que o arquivo de entrada, ele grava o resultado em um arquivo temporário e substitui o arquivo de entrada original (exatamente o mesmo que o que sed -ifaz).

Na GNU sortpágina de informações:

`-o OUTPUT-FILE'
`--output=OUTPUT-FILE'
      Write output to OUTPUT-FILE instead of standard output.  Normally,
      `sort' reads all input before opening OUTPUT-FILE, so you can
      safely sort a file in place by using commands like `sort -o F F'
      and `cat F | sort -o F'.  However, `sort' with `--merge' (`-m')
      can open the output file before reading all input, so a command
      like `cat F | sort -m -o F - G' is not safe as `sort' might start
      writing `F' before `cat' is done reading it.

      On newer systems, `-o' cannot appear after an input file if
      `POSIXLY_CORRECT' is set, e.g., `sort F -o F'.  Portable scripts
      should specify `-o OUTPUT-FILE' before any input files.

e do The Open Group Base Specifications Edição 7 :

-o  output
    Specify the name of an output file to be used instead of the standard 
    output. This file can be the same as one of the input files.
enzotib
fonte
Exatamente ! Funciona ! Não vejo nenhuma pista sobre isso man sort- é um recurso não documentado? É padrão e portátil?
Grzegorz Wierzowiecki 22/01
@GrzegorzWierzowiecki: veja atualização.
enzotib
Boa resposta :).
Grzegorz Wierzowiecki 22/01
1
Em resumo: sort -o <filename> <filename>irá classificar com segurança um arquivo no local.
Phyatt #
11

Você pode usar a spongefunção, que primeiro absorve stdine depois a grava em um arquivo, como:

sort < f | sponge f

A desvantagem spongeé que ele armazenará a saída temporariamente na memória, o que pode ser problemático para arquivos grandes. Caso contrário, você deve gravá-lo em um arquivo primeiro e depois substituir o arquivo original.

Como, no entanto, é apontado por outras respostas, as modificações no local geralmente não são uma boa ideia, pois no meio de um processo (por exemplo, o processo sponge), a máquina pode travar e você pode perder o arquivo original e o novo. É melhor primeiro gravá-lo em um arquivo diferente e depois usar uma mvinstrução atômica (mover).

Willem Van Onsem
fonte
7

É perigoso substituir o arquivo de entrada pelo arquivo de saída, porque se o programa ou o sistema travar enquanto o arquivo está sendo gravado, você perdeu os dois.

Alguns programas (principalmente versões do GNU) têm uma opção no local (por exemplo, -ino perl e GNU sed; -ono tipo GNU). Eles trabalham colocando os dados em um arquivo temporário e depois movendo-os para o lugar. Para programas que não têm essa opção, o spongeutilitário de Colin Watson (incluído no moreutils de Joey Hess ) realiza o trabalho com segurança em qualquer programa (exemplos: posso cutalterar um arquivo no local ?; Como faço para o iconv substituir o arquivo de entrada pelo arquivo convertido saída? ).

Somente nos casos raros em que você não pode recriar o arquivo original com as mesmas permissões é recomendável substituir o arquivo no local. Nesse caso, é melhor salvar a entrada original em algum lugar. E então você pode simplesmente processar a cópia da entrada e enviá-la para o arquivo original.

cp -p f ~/f.backup
sort <~/f.backup >|f
rm ~/f.backup # optional
Gilles
fonte
1
sort -onão é específico do GNU e foi especialmente desenvolvido para substituir o arquivo no local. sortnão pode começar a gravar sua saída antes de ler completamente suas entradas (usa memória ou arquivos temporários para armazenar dados); portanto, é natural que ele possa substituir sua entrada.
Stéphane Chazelas
E, na verdade, é um caso em que o GNU sortnão é POSIX, pois sort -mo file1 file1 file2não é garantido que funcione enquanto os sorts tradicionais sabem como solucionar isso (já lido no Unix V7 nos anos 70).
Stéphane Chazelas
O @JoelCross Odd, sort -ofunciona para mim com o coreutils 8.25 e a propriedade está documentada no manual (observando que esse é apenas o caso na classificação e não na mesclagem). Se você pode reproduzir isso, envie um relatório de erro (indicando a linha de comando exata, o (s) arquivo (s) de entrada exato (s), em que sistema você o está executando e como obteve o binário).
Gilles
4

Use -oou tente o vim-way:

$ ex -s +'%!sort' -cxa file.txt
kenorb
fonte