Classificar usando o padrão personalizado

5

Existe uma maneira de gerar o conteúdo do arquivo usando padrões personalizados?

Por exemplo, ter um arquivo myfile com o seguinte conteúdo:

a
d
b
c

.. como é possível classificá-lo usando o seguinte padrão: imprima linhas iniciando com "b" primeiro, depois imprima as linhas iniciando com "d" e imprima as linhas em ordem alfabética normal, portanto a saída esperada é:

b
d
a
c
    
por Sergey Lukin 12.05.2013 / 13:14

4 respostas

5

Você precisaria usar algo mais do que apenas o comando sort . Primeiro grep as b linhas, depois as d linhas e depois classifique qualquer coisa sem o b ou d no final disso.

grep '^b' myfile > outfile
grep '^d' myfile >> outfile
grep -v '^b' myfile | grep -v '^d' | sort >> outfile
cat outfile

resultará em:

b
d
a
c

Isso pressupõe que as linhas começam com o padrão '%'b e d se for o padrão inteiro ou algo dentro da linha que você pode deixar de circunflexo ( ^ )

Um equivalente de uma linha seria:

(grep '^b' myfile ; grep '^d' myfile ; grep -v '^b' myfile | grep -v '^d' | sort)
    
por 12.05.2013 / 13:18
14

Quando você precisa que os dados sejam classificados além da capacidade de sort , uma abordagem comum é pré-processar os dados para preceder uma chave de classificação, classificar e, finalmente, remover a chave de classificação extra. Por exemplo, aqui, adicione um 0 se uma linha começar com b , um 1 se uma linha começar com d e um 2 caso contrário.

sed -e 's/^b/0&/' -e t -e 's/^d/1&/' -e 't' -e 's/^/2/' |
sort |
sed 's/^.//'

Observe que isso classifica todas as linhas b e d . Se você quiser essas linhas na ordem original, a abordagem mais fácil é dividir as linhas que você deseja deixar sem classificação . Você pode, no entanto, trabalhar a linha original em uma chave de classificação com nl - mas aqui é mais complicado. (Substitua \t por um caractere de tabulação literal se o seu texto não entender essa sintaxe).

nl -ba -nln |
sed 's/^[0-9]* *\t\([bd]\)/\t&/; t; s/^[0-9]* *\t/z\t0\t/' |
sort -k1,1 -k2,2n |
sed 's/^[^\t]*\t[^\t]*\t//'

Como alternativa, use uma linguagem como Perl, Python ou Ruby, que permite especificar facilmente uma função de classificação personalizada.

perl -e 'print sort {($b =~ /^[bd]/) - ($a =~ /^[bd]/) ||
                     $a cmp $b} <>'
python -c 'import sys; sys.stdout.write(sorted(sys.stdin.readlines(), key=lambda s: (0 if s[0]=="b" else 1 if s[0]=="d" else 2), s))'

ou se você quiser deixar as linhas b e d na ordem original:

perl -e 'while (<>) {push @{/^b/ ? \@b : /^d/ ? \@d : \@other}, $_}
         print @b, @d, sort @other'
python -c 'import sys
b = []; d = []; other = []
for line in sys.stdin.readlines():
    if line[0]=="b": b += line
    elif line[0]=="d": d += line
    else: other += line
other.sort()
sys.stdout.writelines(b); sys.stdout.writelines(d); sys.stdout.writelines(other)'
    
por 13.05.2013 / 02:38
4

Uma maneira de resolver isso usando awk seria:

sort myfile | awk '$0 ~ /^b/ || $0 ~ /^d/ {print} $0 !~ /^b/ && $0 !~ /^d/ { a[f++] = $0 } END { for (word = 0; word < f; word++) { print a[word] } }'
    
por 12.05.2013 / 16:23
0
cat file | tr bd '' | LANG=C sort | tr '' bd

Onde os conteúdos intermediários são: (imprimindo CrtA, CrtB como , )

file  | tr-1  | sort  | tr-2
------------------------------
cat     cat     Ⓐat     bat
bed     ⒶeⒷ     ⒶeⒷ     bed
fog     fog     Ⓑay     day
dog     Ⓑog     Ⓑog     dog
egg     egg     cat     cat
day     Ⓑay     egg     egg
kin     kin     fog     fog
lay     lay     get     get
in      in      in      in
bat     Ⓐat     kin     kin
get     get     lay     lay
    
por 05.01.2018 / 11:04

Tags