Journal sort - tri de route

Posté par  .
Étiquettes : aucune
0
12
avr.
2006
Chères lectrices, chers lecteurs,

En ma qualité d'administrateur réseau (dit comme ça, ça en jette, hein?), je suis régulièrement amené à utiliser la commande « route » (bon, là, nettement moins).
Mon problème, c'est que quand la dite commande me renvoie une cinquantaine de routes dans le désordre, je peine un peu à m'y retrouver.

J'ai déjà appris que l'on pouvait trier efficacement une liste d'adresses IP, à l'aide d'un « sort -n -t. -k1,1 -k2,2 -k3,3 -k4,4».
C'est un premier pas.
Seulement la commande « route » commence par produire 2 lignes d'entête avant d'afficher le résultat.
Ces 2 lignes se retrouvent donc dans la moulinette de « sort » et l'affichage s'en retrouve perturbé (bon, OK, rien de désastreux, mais je suis un poil perfectionniste.)

Avec un brin d'imagination, j'ai tenté la mise en série de filtres dans un shell intermédiaire :
route | (head -n 2; sort -n -t. -k1,1 -k2,2 -k3,3)
Hélas, « head » bouffe bien plus que la tête, et « sort » n'a plus rien à se mettre sous la dent. Je ne récupère que les 2 lignes d'entête.
Même résultat en utilisant un « sed -e "n;q" » à la place du « head -n 2 ».

Il s'agit visiblement d'un problème de buffer d'entrée remplit trop avidement, puisque par exemple
ls -l /usr/bin | (head -n 1; cat)me renvoie l'entête « total » suivie de la fin du « ls -l ».
À noter que « ls -l /usr/bin | (dd of=/dev/null bs=8192 count=1; cat) » me renvoie exactement le même résultat (à l'exception de l'entête bien sûr); head utilise donc un buffer de 8 Ko.

Tout cela m'amène à une interrogation plus générale: comment appliquer efficacement plusieurs filtres sur la sortie d'une même commande, l'un sur les n premières lignes, et un autre sur la suite ?

L'idée de la mise en série dans un shell tient pourtant la route, puisque par exemple route | (read a; read b; echo -e "$a\n$b"; sort -n -t. -k1,1 -k2,2 -k3,3) fonctionne.

Faut-il considérer que head, sed, et probablement d'autres sont buggés?
Ces commandes sont-elles sensées absorber plus de données qu'elles ne vont finalement en traiter?
Y aurait-il un ajustement possible quelque part pour éviter cela?

Ou peut-être que j'en demande trop à un simple shell et que ferais mieux de faire du <votre langage de script préféré> ?

Vos commentaires et avis sur la question sont les bienvenus.
  • # et si tu faisais

    Posté par  . Évalué à 3.

    route | tail +3 | sort -n -t. -k1,1 -k2,2 -k3,3
    • [^] # Re: et si tu faisais

      Posté par  . Évalué à 1.

      Et les entêtes? :)

      Ma commande est un exemple.
      Dans ce cas très précis je pourrais aussi réafficher les entêtes à la main, etc.
      Mais tout l'intérêt est dans le problème.
      • [^] # Re: et si tu faisais

        Posté par  . Évalué à 1.

        J'pense qu'il y a pas mal de possibilités, toutes un peu dégueulasse.
        genre:

        [gco@gc]:~% plop=`/sbin/route -n` ; nplop=`echo $plop |wc -l` ; echo $plop |head -n2 ; echo $plop |tail -n$((nplop-2)) | sort -n -t. -k1,1 -k2,2 -k3,3
        Kernel IP routing table
        Destination Gateway Genmask Flags Metric Ref Use Iface
        0.0.0.0 10.1.1.254 0.0.0.0 UG 0 0 0 eth0
        10.1.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
        • [^] # Re: et si tu faisais

          Posté par  . Évalué à 1.

          Oui, bonne solution, merci.

          Je préfère quand même traiter la sortie en un seul flux.
          Voir ma ligne de commande avec les « read ».
          • [^] # Re: et si tu faisais

            Posté par  . Évalué à 1.

            route -n | (head -c 102;sort -n -t. -k1,1 -k2,2 -k3,3)

            cf mon commentaire plus loin sur pourquoi ca marche 'en caractères'. Après, je sais pas si y a toujours autant de caractères. Mais bon, je sais pas pourquoi il y aurait toujours 2 lignes aussi.
            • [^] # Re: et si tu faisais

              Posté par  . Évalué à 1.

              Ouais bien vu.
              Ça reste difficilement portable vers d'autres systèmes, d'autres locales, etc.
      • [^] # Re: et si tu faisais

        Posté par  . Évalué à 0.

        route head -n 2; route | tail +3 | sort -n -t. -k1,1 -k2,2 -k3,3

        Mais un administrateur reseau a-t-il vraiment besoin de cela ? Si c'etait le cas, cet option n'existerait-elle pas deja, depuis le temps que la commande route existe ?
        A moins qu'il ne s'agisse d'un programme de presentation des routes, mais dans ce cas, mieux vaut prendre un langage plus evolue, un langage d'admin, comme le perl, non ?

        Le bonjour chez vous,
        Yves
  • # Commande ip

    Posté par  . Évalué à 2.

    Pourquoi n'utilises-tu pas la commande ip pour afficher les routes ?

    ip route (ou ip r pour aller plus vite) permet, de base, un affichage plus clair


    Package iproute.
    • [^] # Re: Commande ip

      Posté par  . Évalué à 1.

      Merci de la suggestion, je vais jeter un ½il.
    • [^] # Re: Commande ip

      Posté par  . Évalué à 1.

      Franchement je préfère l'affichage de « route », avec un alignement des colonnes etc.
  • # Euh...

    Posté par  . Évalué à 2.

    Avec un
    route -n | (sed 1,2d;sort -n -t. -k1,1 -k2,2 -k3,3)
    ou
    route -n | sed 1,2d | sort -n -t. -k1,1 -k2,2 -k3,3
    le problème n'est plus.

    Et d'ailleurs je ne comprends pas trop l'utilité du
    head -n2
    tout ce que cela fait, c'est retourner les 2 premières lignes de la sortie standard (qui sont ensuite traitées par le sort...)
    • [^] # Re: Euh...

      Posté par  . Évalué à 1.

      Et un truc du genre:
      route -n | tail -n +3 | sort -n -t. -k1,1 -k2,2 -k3,3

      ca ne marche pas ?

      Concernant le coup du head -n 2, je vois pas vraiment où head serait buggé, vu qu'il fait exactement ce que tu lui demandes, cad afficher uniquement les deux premières lignes...
      • [^] # Re: Euh...

        Posté par  . Évalué à 1.

        Non encore une fois, mon objectif est d'afficher :
        1) les deux premières lignes telles quelles, et
        2) les lignes suivantes, triées.
    • [^] # Re: Euh...

      Posté par  . Évalué à 1.

      Alors ta première suggestion non, car la sortie ne sera pas triée.
      Ne pas oublier que sort ne traite que les données qui n'ont pas été traitées par sed.
      Hors sed utilise un buffer de 4 Ko, largement de quoi contenir toutes mes routes.
      Donc sed supprime les 2 lignes et resort la suite telle quelle.

      Et la 2ème non plus, car mon objectif est de conserver les entêtes, pas de les éliminer.

      Ce que je cherche à faire avec le head, c'est lire les 2 premières lignes (et uniquement les 2 premières) et les afficher, pour ensuite ne laisser à sort que les données, hors entêtes.
      • [^] # Re: Euh...

        Posté par  (site web personnel) . Évalué à 2.

        euh, 4Ko = "Largement de quoi traiter toutes tes routes" ?

        donc tu n'es pas administrateur système d'opérateur sous AS ?

        et donc j'aurais rapidement un problème :

        benjamin@gibu:~$ route -n |wc -l
        # quelques instants plus tard ...
        182287

        à mon avis, dès que je vais en extraire des bouts, ca ne tiendra pas dans 4Ko hein ;)
  • # C'est pas un bug, c'est une fonctionnalité (mal comprise?)

    Posté par  . Évalué à 2.

    Ces commandes sont-elles sensées absorber plus de données qu'elles ne vont finalement en traiter?


    Oui. Sinon, sans connaitre la taille des lignes, tu vas sinon faire une lecture (appel système) par caractères et vive l'efficacité.

    head n'a jamais été une commande qui avale des lignes et laisse inchanger le reste. Il faut considerer qu'il prend tout et ne rend que les -n lignes demandé. Dans le cas d'un long ls -l /usr/bin , c'est juste que le programme quitte et s'amuse pas à lire inutilement ce qui reste, ce qui pourrait prendre du temps pour rien.
  • # tee + pipes nommés

    Posté par  . Évalué à 3.

    c'est un peu tarabiscoté mais ça peut marcher je pense :)

    P.e. en utilisant tee (qui balance la sortie sur plusieurs fichiers) et utiliser des pipes nommés à la place des fichiers pour récupérer les 2 première lignes et par ailleurs le reste trié ...

    Dam
    • [^] # Re: tee + pipes nommés

      Posté par  . Évalué à 0.

      En fait j'ai déjà testé. :)

      Non ça ne marche pas.

      Deux cas de figure :

      1) head dans le pipe nommé
      La sortie du pipe nommé arrive sur la sortie standard après la sortie de la commande principale.

      Enfin en clair, route | tee >(head -n 2) | tail +3 ne fonctionne pas, les lignes d'entêtes apparaissent en fin de commande.
      Et il ne s'agit pas juste d'un problème de timing, route | tee >(head -n 2) | (sleep 5; tail +3) donne le même résultat (mais 5 secondes plus tard ;)).

      2) tail dans le pipe nommé
      Dans l'autre sens, route | tee >(tail +3) | head -n 2 ne me renvoie que les entêtes.
      Le head s'applique en fait à la sortie des 2 commandes.

      Je ne suis pas 100% sûr de mon interprétation du résultat, mais enfin ce qui est certain c'est que ça ne fonctionne pas.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.