ordena mas mantém a linha de cabeçalho no topo

52

Estou obtendo a saída de um programa que primeiro produz uma linha que é um conjunto de cabeçalhos de coluna e, em seguida, várias linhas de dados. Eu quero cortar várias colunas desta saída e visualizá-lo classificado de acordo com várias colunas. Sem os cabeçalhos, o corte e a classificação são facilmente executados por meio da opção -k para sort juntamente com cut ou awk para exibir um subconjunto das colunas. No entanto, esse método de classificação mistura os cabeçalhos de coluna com o restante das linhas de saída. Existe uma maneira fácil de manter os cabeçalhos no topo?

    
por jonderry 23.04.2011 / 02:05

11 respostas

52

Roubar a ideia de Andy e torná-la uma função, por isso é mais fácil de usar:

# print the header (the first line of input)
# and then run the specified command on the body (the rest of the input)
# use it in a pipeline, e.g. ps | body grep somepattern
body() {
    IFS= read -r header
    printf '%s\n' "$header"
    "$@"
}

Agora eu posso fazer:

$ ps -o pid,comm | body sort -k2
  PID COMMAND
24759 bash
31276 bash
31032 less
31177 less
31020 man
31167 man
...

$ ps -o pid,comm | body grep less
  PID COMMAND
31032 less
31177 less
    
por 23.04.2011 / 02:44
33

Você pode manter o cabeçalho no topo assim com o bash:

command | (read -r; printf "%s\n" "$REPLY"; sort)

Ou faça isso com o perl:

command | perl -e 'print scalar (<>); print sort { ... } <>'
    
por 23.04.2011 / 02:32
21

Eu encontrei uma boa versão do awk que funciona bem em scripts:

awk 'NR == 1; NR > 1 {print $0 | "sort -n"}'
    
por 10.04.2013 / 14:51
4

Hackear mas efetivo: prefixar 0 em todas as linhas de cabeçalho e 1 em todas as outras linhas antes da classificação. Retire o primeiro caractere após a classificação.

… |
awk '{print (NR <= 2 ? "0 " : "1 ") $0}' |
sort -k 1 -k… |
cut -b 3-
    
por 23.04.2011 / 02:35
3

Aqui está um pouco de ruído mágico da linha perl que você pode canalizar sua saída para classificar tudo, mas manter a primeira linha no topo: perl -e 'print scalar <>, sort <>;'

    
por 23.04.2011 / 08:32
2

Acho que isso é mais fácil.

ps -ef | ( head -n 1 ; sort )

ou isto é possivelmente mais rápido, pois não cria um sub shell

ps -ef | { head -n 1 ; sort ; }

Outros usos interessantes

Misture as linhas depois da linha de cabeçalho

cat file.txt |  ( head -n 1 ; shuf )

inverter linhas após a linha de cabeçalho

cat file.txt |  ( head -n 1 ; tac )
    
por 05.11.2015 / 18:42
1

Eu tentei a solução command | {head -1; sort; } e posso confirmar que realmente estraga tudo - head lê em várias linhas do pipe e, em seguida, gera apenas a primeira. Então, o resto da saída, que head não leu, é passado para sort - NÃO o resto da saída a partir da linha 2!

O resultado é que faltam linhas (e uma linha parcial!) que estavam no início da saída do seu comando (exceto que você ainda tem a primeira linha) - um fato que é fácil de confirmar adicionando um pipe a wc no final do pipeline acima - mas isso é extraordinariamente difícil de rastrear se você não sabe disso! Eu gastei pelo menos 20 minutos tentando descobrir porque eu tinha uma linha parcial (primeiro 100 bytes ou algo assim cortado) na minha saída antes de resolvê-la.

O que acabei fazendo, que funcionou lindamente e não exigia a execução do comando duas vezes, foi:

myfile=$(mktemp)
whatever command you want to run > $myfile

head -1 $myfile
sed 1d $myfile | sort

rm $myfile

Se você precisar colocar a saída em um arquivo, poderá modificá-lo para:

myfile=$(mktemp)
whatever command you want to run > $myfile

head -1 $myfile > outputfile
sed 1d $myfile | sort >> outputfile

rm $myfile
    
por 07.11.2015 / 02:21
0
command | head -1; command | tail -n +2 | sort
    
por 20.05.2014 / 13:48
0

Simples e direto!

<command> | head -n 1; <command> | sed 1d | sort <....>
  • sed nd --- > 'n' especifica o número da linha e 'd' significa excluir.
por 03.11.2015 / 19:05
0

Eu vim aqui procurando uma solução para o comando w . Este comando mostra detalhes de quem está logado e o que eles estão fazendo.

Para mostrar os resultados classificados, mas com os cabeçalhos mantidos no topo (há duas linhas de cabeçalhos), eu decidi:

w | head -n 2; w | tail -n +3 | sort

Obviamente, isso executa o comando w duas vezes e, portanto, pode não ser adequado para todas as situações. No entanto, para sua vantagem, é substancialmente mais fácil de lembrar.

Observe que tail -n +3 significa "mostrar todas as linhas a partir do terceiro" (consulte man tail para obter detalhes).

    
por 19.01.2017 / 09:59
-2

Tente fazer:

wc -l file_name | tail -n $(awk '{print $1-1}') file_name | sort
    
por 11.01.2018 / 22:50