web-dev-qa-db-fra.com

Existe-t-il un moyen d'ignorer les lignes d'en-tête dans un tri UNIX?

J'ai un fichier à champ de largeur fixe que j'essaie de trier à l'aide de l'utilitaire de tri UNIX (Cygwin, dans mon cas).

Le problème est qu'il y a un en-tête de deux lignes en haut du fichier qui est en train d'être trié vers le bas du fichier (chaque ligne d'en-tête commençant par un signe deux-points).

Existe-t-il un moyen de dire que le tri doit être "passer les deux premières lignes non triées" ou spécifier un ordre triant les deux-points en haut, les lignes restantes commençant toujours par un chiffre à 6 chiffres fais le tri sur) si ça aide.

Exemple:

:0:12345
:1:6:2:3:8:4:2
010005TSTDOG_FOOD01
500123TSTMY_RADAR00
222334NOTALINEOUT01
477821USASHUTTLES21
325611LVEANOTHERS00

devrait trier à:

:0:12345
:1:6:2:3:8:4:2
010005TSTDOG_FOOD01
222334NOTALINEOUT01
325611LVEANOTHERS00
477821USASHUTTLES21
500123TSTMY_RADAR00
80
Rob Gilliam
(head -n 2 <file> && tail -n +3 <file> | sort) > newfile

Les parenthèses créent un sous-shell, enveloppant la sortie standard afin que vous puissiez le diriger ou le rediriger comme s'il provenait d'une seule commande.

92
BobS

Si vous n’en avez pas besoin d’utiliser awk, vous pouvez tirer parti des capacités de conduite intégrées de awk.

par exemple.

extract_data | awk 'NR<3{print $0;next}{print $0| "sort -r"}' 

Ceci imprime les deux premières lignes textuellement et dirige le reste à travers sort.

Notez que cela présente l’avantage très spécifique de pouvoir trier de manière sélective les parties d’une entrée raccordée. toutes les autres méthodes suggérées ne trieront que les fichiers simples pouvant être lus plusieurs fois. Cela fonctionne sur n'importe quoi.

41
Dave

Voici une version qui fonctionne sur les données piped:

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

Si votre en-tête comporte plusieurs lignes:

(for i in $(seq $HEADER_ROWS); do read -r; printf "%s\n" "$REPLY"; done; sort)

Cette solution est de ici

26
freeseek

Vous pouvez utiliser tail -n +3 <file> | sort ... (tail affichera le contenu du fichier à partir de la 3ème ligne).

6
Anton Kovalenko
head -2 <your_file> && nawk 'NR>2' <your_file> | sort

exemple:

> cat temp
10
8
1
2
3
4
5
> head -2 temp && nawk 'NR>2' temp | sort -r
10
8
5
4
3
2
1
4
Vijay

Dans des cas simples, sed peut faire le travail avec élégance:

    your_script | (sed -u 1q; sort)

ou équivalent,

    cat your_data | (sed -u 1q; sort)

La clé est dans le 1q - affiche la première ligne (en-tête) et quitte (laissant le reste de l'entrée à sort).

Pour l'exemple donné, 2q fera l'affaire.

Le commutateur -u (non mis en mémoire tampon) est requis pour les seds (notamment les GNU) qui liraient autrement l'entrée en morceaux, consommant ainsi les données que vous souhaitez parcourir sort.

1
Andrea

Il ne faut que 2 lignes de code ...

head -1 test.txt > a.tmp; 
tail -n+2 test.txt | sort -n >> a.tmp;

Pour une donnée numérique, -n est requis. Pour le tri alpha, le -n n'est pas requis.

Exemple de fichier:
$ cat test.txt

entête
8
5
100
1
-1 

Résultat:
$ cat a.tmp

entête
-1
1
5
8
100

1
Ian Sherbin

C’est la même chose que Ian Sherbin, mais ma mise en œuvre est la suivante: -

cut -d'|' -f3,4,7 $arg1 | uniq > filetmp.tc
head -1 filetmp.tc > file.tc;
tail -n+2 filetmp.tc | sort -t"|" -k2,2 >> file.tc;
0
Bik

Voici une fonction bash shell dérivée des autres réponses. Il gère à la fois les fichiers et les pipes. Le premier argument est le nom du fichier ou '-' pour stdin. Les arguments restants sont passés pour trier. Quelques exemples:

$ hsort myfile.txt
$ head -n 100 myfile.txt | hsort -
$ hsort myfile.txt -k 2,2 | head -n 20 | hsort - -r

La fonction shell:

hsort ()
{
   if [ "$1" == "-h" ]; then
       echo "Sort a file or standard input, treating the first line as a header.";
       echo "The first argument is the file or '-' for standard input. Additional";
       echo "arguments to sort follow the first argument, including other files.";
       echo "File syntax : $ hsort file [sort-options] [file...]";
       echo "STDIN syntax: $ hsort - [sort-options] [file...]";
       return 0;
   Elif [ -f "$1" ]; then
       local file=$1;
       shift;
       (head -n 1 $file && tail -n +2 $file | sort $*);
   Elif [ "$1" == "-" ]; then
       shift;
       (read -r; printf "%s\n" "$REPLY"; sort $*);
   else
       >&2 echo "Error. File not found: $1";
       >&2 echo "Use either 'hsort <file> [sort-options]' or 'hsort - [sort-options]'";
       return 1 ;
   fi
}
0
JonDeg

Donc, voici une fonction bash où les arguments sont exactement comme sort. Fichiers de support et pipes.

function skip_header_sort() {
    if [[ $# -gt 0 ]] && [[ -f ${@: -1} ]]; then
        local file=${@: -1}
        set -- "${@:1:$(($#-1))}"
    fi
    awk -vsargs="$*" 'NR<2{print; next}{print | "sort "sargs}' $file
}

Comment ça marche. Cette ligne vérifie s'il y a au moins un argument et si le dernier argument est un fichier.

    if [[ $# -gt 0 ]] && [[ -f ${@: -1} ]]; then

Ceci enregistre le fichier dans un argument séparé. Puisque nous sommes sur le point d'effacer le dernier argument.

        local file=${@: -1}

Ici, nous supprimons le dernier argument. Puisque nous ne voulons pas le passer comme un argument de tri.

        set -- "${@:1:$(($#-1))}"

Enfin, nous faisons la partie awk, en passant les arguments (moins le dernier argument s'il s'agissait du fichier) à trier dans awk Cela a été suggéré par Dave, et modifié pour prendre les arguments de tri. Nous nous basons sur le fait que $file sera vide si nous pipingons, donc ignoré.

    awk -vsargs="$*" 'NR<2{print; next}{print | "sort "sargs}' $file

Exemple d'utilisation avec un fichier séparé par des virgules.

$ cat /tmp/test
A,B,C
0,1,2
1,2,0
2,0,1

# SORT NUMERICALLY SECOND COLUMN
$ skip_header_sort -t, -nk2 /tmp/test
A,B,C
2,0,1
0,1,2
1,2,0

# SORT REVERSE NUMERICALLY THIRD COLUMN
$ cat /tmp/test | skip_header_sort -t, -nrk3
A,B,C
0,1,2
2,0,1
1,2,0
0
flu

Avec Python:

import sys
HEADER_ROWS=2

for _ in range(HEADER_ROWS):
    sys.stdout.write(next(sys.stdin))
for row in sorted(sys.stdin):
    sys.stdout.write(row)
0
crusaderky