Classificação exclusiva: redirecione a saída para o mesmo arquivo

14

Existe alguma maneira curta de salvar a saída do tubo no mesmo arquivo processado. Por exemplo, é isso que estou realmente fazendo

$ cat filename | sort | uniq > result
$ rm -f filename
$ mv result filename

Eu queria saber se havia uma maneira de fazê-lo em apenas uma linha (não anexando esses comandos usando &&)

Este não é o caminho, mas para ter uma idéia

$ cat filename | sort | uniq > filename
whitenoisedb
fonte
2
echo $(cat filename | sort | uniq > result) > filenameou alguma coisa ? Só de passagem, não tenho tempo para tentar.
MrVaykadji
1
@redraw: UUOC, consulte en.wikipedia.org/wiki/Cat_(Unix)#Useless_use_of_cat
cuonglm

Respostas:

18

Você pode usar spongea partir moreutils pacote:

LC_ALL=C sort -u filename | sponge filename

Você também não precisa canalizar uniq, pois quando sorttem -uopção para linhas exclusivas ao classificar.

Observe que no sistema GNU com localidades UTF-8, sort -uou sort | uniqnão, você forneceu linhas únicas, mas a primeira da sequência de linhas que são iguais na localidade atual.

$ printf '%b\n' '\U2460' '\U2461' | LC_ALL=en_US.utf8 sort | LC_ALL=en_US.utf8 uniq

te deu apenas . Alterar a localidade para C força a ordem de classificação com base nos valores de bytes:

$ export LC_ALL=C
$ printf '%b\n' '\U2460' '\U2461' | LC_ALL=C sort | LC_ALL=C uniq

cuonglm
fonte
12

Você não precisa de nenhum comando extra como cate uniqtambém sem usar o rmcomando e o mvcomando para remover e renomear o nome do arquivo. basta usar o comando simples.

sort -u filename -o filename


 -u, --unique
        with -c, check for strict ordering; without -c, output only  the
        first of an equal run

 -o, --output=FILE
        write result to FILE instead of standard output

Como isso funciona?

sortO comando ordena seu nome de arquivo e, com a -uopção, remove linhas duplicadas dele. em seguida, com a -oopção grava a saída no mesmo arquivo com o método no local.

αғsнιη
fonte
3
Se o sistema travar quando sortestiver em execução, você perderá o arquivo original.
cuonglm
@Gnouc Então, isso é o fim do azar !! : '(
αғsнιη 26/09
1
obrigado! neste exemplo, com o 'sort' particularmente, devo fazer isso. No entanto, eu estava pensando em um caso geral. @ Gnouc, haha ​​não há como pensar que se isso não aconteceu com você, certo?
whitenoisedb
3

Seu exemplo sugerido (abaixo) não funciona porque você realmente está lendo e gravando no mesmo arquivo simultaneamente.

$ cat filename | sort | uniq > filename

A idéia com um canal ou redirecionamento é que o comando no lado esquerdo e direito de cada canal ou redirecionamento seja executado simultaneamente, em paralelo. O comando à direita processa as informações conforme são entregues a partir do comando à esquerda, enquanto o comando à esquerda ainda está em execução.

Para que seu cenário funcione, o comando que lê do arquivo precisaria ser concluído antes que o comando que grava no arquivo seja iniciado. Para que isso funcione, você precisará redirecionar a saída para um local temporário primeiro e, depois que terminar, envie-o do local temporário de volta para o arquivo.

Uma maneira melhor de fazer isso é basicamente como no exemplo anterior, em que você redireciona para um arquivo temporário e depois renomeia esse arquivo para o original (exceto que você não precisa excluir o arquivo primeiro, porque a movimentação exclui qualquer destino existente) .

$ cat filename | sort | uniq > result
$ mv -f result filename

Você também pode salvá-lo em uma variável de sequência, exceto que só funciona quando os dados são pequenos o suficiente para caberem na memória de uma só vez.

thomasrutter
fonte
Como alguém publicado em uma edição sugerida, você pode alterar cat filename | sortpara apenas sort filename- caté desnecessário aqui.
thomasrutter
Meu exemplo abaixo não era o caminho para fazê-lo. Obrigado pela clarificação. catpoderia ser desnecessário neste caso, mas eu estava focando na parte de redirecionamento.
whitenoisedb
1
Eu estava explicando por que o exemplo abaixo não funcionaria. Eu sei que você sabia que não funcionava.
thomasrutter
Obrigado por esclarecer! Na verdade, eu não sabia o que realmente estava acontecendo.
whitenoisedb
2

Você pode usar o teecomando:

sort -u filename | tee filename > /dev/null

O teecomando lê da entrada padrão e grava na saída e nos arquivos padrão .

Sylvain Pineau
fonte
2
Isso não funciona para mim.
Pjvandehaar 18/10/2015
3
Isso não funciona askubuntu.com/a/752451
Steven Penny
Isso faz o trabalho para mim. por exemplo, para mover uma linha para o final de um arquivo: (cat ~/file | grep -v 3662 ; printentry 3662) | tee ~/file > /dev/nullfunciona. Como o post original, isso não funciona se você apenas > ~/filesem o tee. Tee parece semelhante aqui sort -o file, que grava no arquivo nomeado sem continuar o mesmo canal.
21417 Joshua Goldberg
Espere, desculpe! Eu já vi empiricamente que isso irá imprevisivelmente perder dados, conforme explicado no link do @Steven. Faça um arquivo com os números 1..9 em 9 linhas. O seguinte funcionará várias vezes e, ocasionalmente, remova todos os dados do arquivo: (cat x | grep -v 7 ; echo 7) | tee x > /dev/null; cat x Eu recomendo um arquivo temporário e / mvou talvez a solução do link do @ Steven.
19377 Joshua Goldberg
@JoshuaGoldberg, você viu minha resposta nesta página?
Steven Penny
0

Você pode usar o Vim no modo Ex:

ex -sc 'sort u|x' filename
  1. sort u classificar único

  2. x escreva se as alterações foram feitas (elas têm) e saia

Steven Penny
fonte