Bash: comment supprimer les doublons d'un tableau indicé?

C’est une mauvaise habitude :slight_smile:

Le réflexe doit plutôt être d’analyser précisément le contenu à traiter pour identifier la commande juste nécessaire. Dans le cas présent, pas besoin de awk.

Fonction cdp:

cdp() { [ -d "$1" ] && cd $1 && pushd $1 || echo  "$1 n'est pas un répertoire" ;}

TEST:

$ dirs -c
$ for x in usr etc boot etc usr ; do cdp  /$x ; done

$ dirs
  /usr /usr /etc /boot /etc /usr

$ dirs -p | sort -u
  /boot
  /etc
  /usr

Oui @Verner, sous réserve qu’un jeu d’essai soit fourni. Ce qui a été fait mais trop tardivement. A la place on a eu au départ seulement un script pas des plus courts ou des plus lisibles pour ce genre de problème.

Effectivement, un problème bien posé est déjà à moitié résolu. C’est vrai dans tous les domaines.
Il faut parfois deviner quel est le réel sujet, lorsque son titre ne reflète pas précisément la description du problème, qui n’est pas dans le cas présent un problème général de ‹ tableau indicé ›, mais juste une liste de répertoires.
Plus généralement, awk est bien sûr l’outil adapté pour le traitement de tableaux, ou de contenu beaucoup plus complexe.
awk est ultra-puissant (comme sed), mais demande un effort initial non négligeable (pour ne pas dire important) pour pénétrer son univers impitoyable, et sa logique pas immédiate.
On voit dans les messages précédents qu’on peut vite bloquer sur un problème de virgule déjà pour une opération très simple.

Concernant l’usage de ‹ dirs / pushd ›, un script n’est pas adapté puisque l’environnement du terminal en cours d’usage ne sera pas directement interprété par le script. Exporter des variables ‹ builtin › vers un script est confus et inutile.

Pour résumer, la fonction suivante permet de:
1 - changer de dossier en le mémorisant;
2 - ‹ -n › : compter le nombre de dossiers enregistrés;
3 - signaler en cas d’erreur de nom de dossier;
4 - sans argument, affiche la liste filtrée/triée des dossiers enregistrés.

cdp() { if [ -z "$1" ] ;   then dirs -p | sort -u
      elif [ $1 = '-n' ] ; then dirs -p | sort -u | sed -n '$='
      elif [ -d $1 ] ; then pushd $1 >/dev/null
      else echo "$1 n'est pas un répertoire"
        fi
}

Ou en version plus compacte avec affichage total nombre de dossiers uniques enregistrés, en absence d’argument::

cdp() { [ -d "$1" ] && pushd $1 >/dev/null && return
        [ "$1" ] && echo "$1 n'est pas un répertoire" || \
        dirs -p | sort -u | awk '1;END {print "T = "NR}'
}

Quelques observations complémentaires:
• le problème de l’usage de ‹ sort › est qu’il casse la chronologie des dossiers;
• ‹ pushd › remplit la pile de dossiers par le haut, alors qu’il semble plus naturel que le dernier dossier atteint soit le dernier.

La version suivante propose un comportement plus naturel.

cdp() { [ -d "$1" ] && pushd $1 &>/dev/null && return
        [ "$1" ] && echo "$1 n'est pas un répertoire" || dirs -p |
        awk '!_[$1]++' | tac | awk '{print NR,$0}'
}

TEST:

$ dirs -c
$ for x in usr etc usr etc boot home boot ; do cdp  /$x ; done

$ cdp
  1 /usr
  2 /etc
  3 /home
  4 /boot

edit: dirs -lp compris en zsh, mais pas par bash.

2 J'aime

Merci à tous les trois, vous m’avez conduit bien au delà de mes espérances naïves.

Pourquoi?
Un alias n’est-il pas un simple texte recopié sur la ligne de commande à son appel?
Que peut faire un pipe, un enchainement de commandes qui soit différent d’une frappe manuelle, plus longue et surtout plus exposée à une erreur?