web-dev-qa-db-fra.com

trier mais garder la ligne d'en-tête en haut

J'obtiens la sortie d'un programme qui produit d'abord une ligne qui est un tas d'en-têtes de colonne, puis un tas de lignes de données. Je souhaite couper différentes colonnes de cette sortie et la visualiser triée en fonction de différentes colonnes. Sans les en-têtes, la découpe et le tri s'effectuent facilement via le -k option pour sort avec cut ou awk pour afficher un sous-ensemble des colonnes. Cependant, cette méthode de tri mélange les en-têtes de colonne avec le reste des lignes de sortie. Existe-t-il un moyen simple de conserver les en-têtes en haut?

63
jonderry

Voler l'idée d'Andy et en faire une fonction pour qu'elle soit plus facile à utiliser:

# 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"
    "$@"
}

Maintenant je peux faire:

$ 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
66
Mikel

Vous pouvez garder l'en-tête en haut comme ceci avec bash:

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

Ou faites-le avec Perl:

command | Perl -e 'print scalar (<>); print sort { ... } <>'
41
Andy

J'ai trouvé ne belle version awk qui fonctionne bien dans les scripts:

awk 'NR == 1; NR > 1 {print $0 | "sort -n"}'
30
Michael Kuhn

Hackish mais efficace: préfixe 0 à toutes les lignes d'en-tête et 1 à toutes les autres lignes avant le tri. Supprimez le préfixe après le tri.

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

Voici un peu de bruit magique sur la ligne Perl à travers lequel vous pouvez diriger votre sortie pour tout trier, mais gardez la première ligne en haut: Perl -e 'print scalar <>, sort <>;'

4
Ryan C. Thompson

J'ai essayé le command | {head -1; sort; } solution et peut confirmer que ça fait vraiment foirer les choses --head lit plusieurs lignes dans le tube, puis sort juste la première. Donc le reste de la sortie, que head n'a pas lu, est passé à sort-- PAS le reste de la sortie à partir de la ligne 2!

Le résultat est qu'il vous manque des lignes (et une ligne partielle!) Qui étaient au début de la sortie de votre commande (sauf que vous avez toujours la première ligne) - un fait qui est facile à confirmer en ajoutant un tube à wc à la fin du pipeline ci-dessus - mais c'est extrêmement difficile à retracer si vous ne le savez pas! J'ai passé au moins 20 minutes à essayer de comprendre pourquoi j'avais une ligne partielle (les 100 premiers octets environ) dans ma sortie avant de la résoudre.

Ce que j'ai fini par faire, qui fonctionnait magnifiquement et ne nécessitait pas d'exécuter la commande deux fois, était:

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

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

rm $myfile

Si vous devez placer la sortie dans un fichier, vous pouvez le modifier pour:

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

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

rm $myfile
2
Wildcard

Je pense que c'est plus simple.

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

ou ce qui est peut-être plus rapide car il ne crée pas de sous-shell

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

Autres utilisations intéressantes

mélanger les lignes après la ligne d'en-tête

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

inverser les lignes après la ligne d'en-tête

cat file.txt |  ( head -n 1 ; tac )
1
user2449151
command | head -1; command | tail -n +2 | sort
0
Sarva

Je suis venu ici à la recherche d'une solution pour la commande w. Cette commande affiche les détails de qui est connecté et ce qu'il fait.

Pour afficher les résultats triés, mais avec les en-têtes conservés en haut (il y a 2 lignes d'en-têtes), j'ai choisi:

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

Évidemment, cela exécute la commande w deux fois et peut donc ne pas convenir à toutes les situations. Cependant, à son avantage, il est beaucoup plus facile à retenir.

Notez que le tail -n +3 signifie "afficher toutes les lignes à partir du 3ème" (voir man tail pour plus de détails).

0
Robert

Simple et direct!

<command> | head -n 1; <command> | sed 1d | sort <....>
  • sed nd ---> 'n' spécifie le numéro de ligne et 'd' signifie supprimer.
0
Jatsui