Eu encontrei uma maneira de fazer isso de maneira fácil e eficiente usando uma linha no bash:
sort --field-separator=':' --key=3 file.txt > fileSorted.txt
Eu tenho um arquivo que tem linhas file.txt
assim:
www.site.com/230207|Sophie Rundle title: Episodes|5irko3ke
www.site.com/228264|Camilla Luddington title: Balifornication|5423234
www.site.com/228592|Sarah Power title: Californication|23423423
www.site.com/229022|Ali Cobrin title: American Reunion|tgkmktgkmtg
www.site.com/190074|Eva Green title: The Dreamers|rfrrfrf
Eu quero que ele seja classificado em fileSorted.txt
em ordem alfabética pela palavra que vem depois de "title", então o resultado seria:
www.site.com/229022|Ali Cobrin title: American Reunion|tgkmktgkmtg
www.site.com/228592|Sarah Power title: Balifornication|23423423
www.site.com/228264|Camilla Luddington title: Californication|5423234
www.site.com/230207|Sophie Rundle title: Episodes|5irko3ke
www.site.com/190074|Eva Green title: The Dreamers|rfrrfrf
Eu sei que temos que usar o comando sort
, então eu tentei:
sort --field-separator='title:' --key=1 file.txt > fileSorted.txt
mas eu tenho esse resultado:
sort: multi-character tab ‘title:’
Eu tentei pesquisar pela internet, mas não consegui "encontrar uma solução". Como posso classificar o arquivo da maneira que desejo como explicado acima? O arquivo tem 100 mil linhas, portanto, o desempenho é importante.
Talvez simplista demais (não funcionará corretamente se houver campos em que o nome do autor tenha um caractere ":"), mas você pode simplesmente classificar no campo ":" com o comando
sort -t: -k2 del.file
Use sed
para alterar temporariamente a sequência. Este exemplo faz com que seja um controle A :
#!/bin/sh
SEP=$(echo x|tr x 'www.site.com/229022|Ali Cobrin title: American Reunion|tgkmktgkmtg
www.site.com/228264|Camilla Luddington title: Balifornication|5423234
www.site.com/228592|Sarah Power title: Californication|23423423
www.site.com/230207|Sophie Rundle title: Episodes|5irko3ke
www.site.com/190074|Eva Green title: The Dreamers|rfrrfrf
1')
sed -e "s/title:/$SEP/" file.txt | \
sort -k2 -t "$SEP" --key=1 |\
sed -e "s/$SEP/title:/" > fileSorted.txt
dá
#!/bin/sh
SEP=$(echo x|tr x 'www.site.com/229022|Ali Cobrin title: American Reunion|tgkmktgkmtg
www.site.com/228264|Camilla Luddington title: Balifornication|5423234
www.site.com/228592|Sarah Power title: Californication|23423423
www.site.com/230207|Sophie Rundle title: Episodes|5irko3ke
www.site.com/190074|Eva Green title: The Dreamers|rfrrfrf
1')
sed -e "s/title:/$SEP/" file.txt | \
sort -k2 -t "$SEP" --key=1 |\
sed -e "s/$SEP/title:/" > fileSorted.txt
No seu exemplo, você estava classificando desde o começo da linha. Com base nos comentários, você pretendia classificar pelos dados iniciados após a sequência "title:"
, exigindo a opção -k2
. (Eu mudei a opção de separação para POSIX também).
Para referência, POSIX:
Você não disse quais ferramentas você queria usar, e é sempre bom ter opções, então aqui está uma solução perl para acompanhar a solução sed / sort de Thomas.
$ cat file.txt
www.site.com/230207|Sophie Rundle title: Episodes|5irko3ke
www.site.com/228264|Camilla Luddington title: Balifornication|5423234
www.site.com/228592|Sarah Power title: Californication|23423423
www.site.com/229022|Ali Cobrin title: American Reunion|tgkmktgkmtg
www.site.com/190074|Eva Green title: The Dreamers|rfrrfrf
$ cat sortfile.pl
#!/usr/bin/perl --
use strict;
use warnings;
my @lines;
while (<>)
{
push @lines, "$1\x00$_" if /title: (.*)/;
}
foreach (sort @lines)
{
s/.*\x00//;
print $_;
}
$ ./sortfile.pl file.txt
www.site.com/229022|Ali Cobrin title: American Reunion|tgkmktgkmtg
www.site.com/228264|Camilla Luddington title: Balifornication|5423234
www.site.com/228592|Sarah Power title: Californication|23423423
www.site.com/230207|Sophie Rundle title: Episodes|5irko3ke
www.site.com/190074|Eva Green title: The Dreamers|rfrrfrf
O conceito é copiar o texto que você deseja classificar para a frente, classificar e remover o texto copiado. As partes principais são:
while (<>)
{
push @lines, "$1\x00$_" if /title: (.*)/;
}
Isso faz um loop em todas as linhas de todos os arquivos nomeados na linha de comando (ou na entrada padrão, se não houver nenhum) e lê cada linha em $_
. O if
no final da terceira linha certifica-se de que a linha se parece com uma que queremos processar e salva tudo depois de title:
in $1
. O push
, em seguida, envia uma linha para @lines
, que contém o título (de $1
), um separador que não deve ocorrer em um título (ASCII nul
) e o restante da linha. Quando esse loop é feito, todas as linhas estão em @lines
com o título copiado para a frente.
foreach (sort @lines)
{
s/.*\x00//;
print $_;
}
Isso faz um loop sobre todas as linhas acumuladas em @lines
depois de classificá-las. Porque o título foi copiado para o início de cada linha, as linhas são classificadas por título. O s/.*\x00//;
retira o título e o separador ASCII nul
, restaurando a linha para a forma original. O print
, em seguida, imprime toda a linha (restaurada).
Tags command-line unix sorting