awk + coller pour nettoyer PATH?

J'ai vu ce code dans les files init .cshrc sur quelques machines. Je suis passé par quelques tutoriels awk en essayant de comprendre comment cela fonctionne, mais je suis toujours incapable de le déchiffrer.

 setenv PATH `echo $PATH | awk 'NF&&\\!x[$0]++' RS='[:|\n]' | paste -sd:` 

Qu'est ce que ça fait?

Ne fonctionne pas pour moi avec les backslashes mais je peux vous expliquer ceci:

 echo "$PATH" | awk 'NF && !x[$0]++' RS='[:|\n]' 

Le séparateur d'logging ( RS ) est réglé sur l'un des caractères ":", "|" et nouvelle ligne. $PATH est généralement juste une ligne avec des éléments séparés par ":". Cela fait awk se comporter comme les paths n'étaient pas séparés par ":" mais chacun sur sa propre ligne.

NF signifie que les lignes vides ( NF == 0 ) sont ignorées. x est un tableau associatif avec les paths comme indice. !x[$0]++ signifie que la "ligne" est ignorée si x[$0] est supérieur à 0. Le résultat est que chaque ligne est sortie une seule fois. Lors de la première exécution, x[$0] est augmenté de sorte que dans les exécutions suivantes !x[$0] est faux.

Cet exemple montre la fréquence de tous les éléments après le traitement de la dernière ligne:

 echo "a:b:a:c:a:b" | awk 'NF && !x[$0]++;END {for (var in x) print var ": " x[var]}' RS='[:|\n]' a b c a: 3 b: 2 c: 1 

Comme décrit par Hauke, l'intention ici est de n'avoir que des éléments uniques dans la variable $PATH .

Ce n'est pas un script awk portable, RS est souvent limité à un seul caractère et non à une expression régulière. Une alternative plus portable serait quelque chose comme ceci:

 setenv PATH `printf "%s" "$PATH" | awk '{ sub("/$","") }; x[$0]++ < 1' RS=: | paste -s -d : -` 

Testé en tcsh avec gawk et nawk.

Quelques points à noter:

  • la nouvelle ligne étrangère est évitée en utilisant printf .
  • le ! , qui signifie extension de l'historique à tcsh, peut être remplacé en vérifiant si la valeur est inférieure à 1.
  • les séparateurs de path de terminaison sont supprimés avec sub() .