Classificando um arquivo delimitado por tabulação

180

Eu tenho dados com o seguinte formato:

foo<tab>1.00<space>1.33<space>2.00<tab>3

Agora, tentei classificar o arquivo com base no último campo decrescente. Eu tentei os seguintes comandos, mas não foi classificado como esperado.

$ sort -k3nr file.txt  # apparently this sort by space as delimiter

$ sort -t"\t" -k3nr file.txt
  sort: multi-character tab `\\t'

$ sort -t "`/bin/echo '\t'`" -k3,3nr file.txt
  sort: multi-character tab `\\t'

Qual é o caminho certo para fazer isso?

Aqui estão os dados de amostra .

neversaint
fonte

Respostas:

312

Usando o bash , isso fará o truque:

$ sort -t$'\t' -k3 -nr file.txt

Observe o sinal de cifrão na frente da string entre aspas simples. Você pode ler sobre isso nas seções de cotação ANSI-C da página de manual do bash .

Lars Haugseth
fonte
2
Use '"'"' para usá-lo dentro de um alias.
Pablo #
você pode mostrar como passar esse delímetro para classificar dentro de um comando awk? como em awk '{print $0 | "sort -nr" > "outfile" }' datafile, exceto com um delimitador de tabulação escapado enviado ao comando de classificação.
Merlin
11

Por padrão, o delimitador de campo não está em branco para transição em branco, portanto, a guia deve funcionar perfeitamente.

No entanto, as colunas são indexadas na base 1 e na base 0, então você provavelmente deseja

sort -k4nr file.txt

para classificar file.txt pela coluna 4 numericamente na ordem inversa. (Embora os dados na pergunta tenham até cinco campos, o último campo seria o índice 5.)

Laalto
fonte
4
Isso funcionará apenas se o número de caracteres de espaço entre os campos separados por tabulação for o mesmo para todas as linhas de entrada.
Lars Haugseth
5

Você precisa colocar um caractere de tabulação real após o -t \ e, para fazer isso em um shell, pressiona ctrl-v e, em seguida, o caractere de tabulação. A maioria dos shells que usei suporta esse modo de entrada literal da guia.

Cuidado, porém, porque copiar e colar de outro local geralmente não preserva as guias.

Brian Carlsen
fonte
Essa é a melhor resposta (mais portátil). O emacs também permite fazer isso no modo 'inserção entre aspas': C-q <tab>por exemplo. Eu acho que também está ^Vno nano.
Wyatt8740
3

A solução $ não funcionou para mim. No entanto, ao colocar o caractere de tabulação no comando: sort -t '' -k2

Lloyd
fonte
1
Use <C-v><Tab>para inserir tabulação caso a tecla tab seja usada para preenchimento automático em seu shell.
Júda Ronén
1
A citação ANSI $'\t'funciona em ksh, zsh e bash. O shell Bourne não suporta. Veja esta postagem: unix.stackexchange.com/a/371873/201820
codeforester
1

passe através de algo parecido awk '{ print print $1"\t"$2"\t"$3"\t"$4"\t"$5 }'. Isso mudará os espaços para tabulações.

Michiel Buddingh
fonte
@MB: Eu preciso manter o espaço intacto.
neversaint
1
Sem dúvida, há uma maneira mais limpa de fazer isso, mas nada impede que você faça o pipeline através do awk, altere os espaços para guias, classifique os dados e depois faça o pipeline no awk novamente, alterando as guias novamente para espaços.
Michiel Buddingh
1
Isso não funcionará se houver uma mistura de guias e espaços que você deseja preservar.
James Thompson
1

Em geral, manter dados como esse não é algo muito bom se você puder evitá-los, porque as pessoas estão sempre confundindo guias e espaços.

Resolver seu problema é muito simples em uma linguagem de script como Perl, Python ou Ruby. Aqui está um exemplo de código:

#!/usr/bin/perl -w

use strict;

my $sort_field = 2;
my $split_regex = qr{\s+};

my @data;
push @data, "7 8\t 9";
push @data, "4 5\t 6";
push @data, "1 2\t 3";

my @sorted_data = 
    map  { $_->[1] }
    sort { $a->[0] <=> $b->[0] }
    map  { [ ( split $split_regex, $_ )[$sort_field], $_ ] }
    @data;

print "unsorted\n";
print join "\n", @data, "\n";
print "sorted by $sort_field, lines split by $split_regex\n";
print join "\n", @sorted_data, "\n";
James Thompson
fonte
1

Eu queria uma solução para a classificação Gnu no Windows, mas nenhuma das soluções acima funcionou para mim na linha de comando.

Usando a pista de Lloyd, o seguinte arquivo em lotes (.bat) funcionou para mim.

Digite o caractere de tabulação entre aspas duplas.

C:\>cat foo.bat

sort -k3 -t"    " tabfile.txt
Lawrence Noronha
fonte
1
Sim, o truque aqui é colocá-lo em um arquivo .bat, caso contrário não vai funcionar
Carlos Rendon
1

Eu estava tendo esse problema com a classificação no cygwin em um shell bash ao usar 'classificação numérica geral'. Se eu especifiquei -t$'\t' -kFg, onde F é o número do campo, ele não funcionou, mas quando eu especifiquei ambos -t$'\t'e -kF,Fg(por exemplo, -k7,7gpara o 7º campo) funcionou. -kF,Fgsem o -t$'\t'não funcionou.

Danny
fonte
0

Se você quiser facilitar as coisas apenas com guias, substitua os espaços por guias:

tr " " "\t" < <file> | sort <options>
The Unfun Cat
fonte
Meu tr não lê arquivos, apenas transmite XD. usage: tr [-Ccsu] string1 string2
The Unfun Cat
1
tr string1 string2 <some-file. Tudo pode ler um arquivo, desde que possa ler stdin.
Randal Schwartz
0

A resposta de Lars Haugseth funcionou apenas na linha de comando para mim, onde ocorre esse erro se executado a partir de um script de shell:

classificar: guia com vários caracteres '$ \ t'

A solução, se estiver codificada em um script de shell, se alguém estiver olhando

sort -t'    '

o caractere de tabulação está entre as aspas.

mightyandweakcoder
fonte