Entfernen Sie doppelte $PATH-Einträge mit dem awk-Befehl

Entfernen Sie doppelte $PATH-Einträge mit dem awk-Befehl

Ich versuche, eine Bash-Shell-Funktion zu schreiben, mit der ich doppelte Kopien von Verzeichnissen aus meiner Umgebungsvariable PATH entfernen kann.

Mir wurde gesagt, dass dies mit einem einzeiligen Befehl unter Verwendung des awkBefehls möglich ist, aber ich kann nicht herausfinden, wie das geht. Weiß jemand, wie das geht?

Antwort1

Wenn Sie noch keine Duplikate darin haben PATHund nur Verzeichnisse hinzufügen möchten, wenn sie noch nicht vorhanden sind, können Sie dies problemlos allein mit der Shell tun.

for x in /path/to/add …; do
  case ":$PATH:" in
    *":$x:"*) :;; # already there
    *) PATH="$x:$PATH";;
  esac
done

Und hier ist ein Shell-Snippet, das Duplikate aus entfernt $PATH. Es geht die Einträge einzeln durch und kopiert diejenigen, die noch nicht gesehen wurden.

if [ -n "$PATH" ]; then
  old_PATH=$PATH:; PATH=
  while [ -n "$old_PATH" ]; do
    x=${old_PATH%%:*}       # the first remaining entry
    case $PATH: in
      *:"$x":*) ;;          # already there
      *) PATH=$PATH:$x;;    # not there yet
    esac
    old_PATH=${old_PATH#*:}
  done
  PATH=${PATH#:}
  unset old_PATH x
fi

Antwort2

Hier ist einverständlichEinzeiler-Lösung, die alles richtig macht: Duplikate entfernt, die Reihenfolge der Pfade beibehält und am Ende keinen Doppelpunkt hinzufügt. Sie sollte Ihnen also einen deduplizierten PATH geben, der genau dasselbe Verhalten wie das Original bietet:

PATH="$(perl -e 'print join(":", grep { not $seen{$_}++ } split(/:/, $ENV{PATH}))')"

Es teilt einfach am Doppelpunkt ( split(/:/, $ENV{PATH})), filtert mithilfe von „uses“ grep { not $seen{$_}++ }alle wiederholten Instanzen von Pfaden mit Ausnahme des ersten Vorkommens heraus, fügt dann die verbleibenden durch Doppelpunkte getrennt wieder zusammen und druckt das Ergebnis ( print join(":", ...)).

Wenn Sie etwas mehr Struktur und die Möglichkeit zum Entfernen von Duplikaten anderer Variablen wünschen, probieren Sie diesen Code-Schnipsel aus, den ich derzeit in meiner eigenen Konfiguration verwende:

# Deduplicate path variables
get_var () {
    eval 'printf "%s\n" "${'"$1"'}"'
}
set_var () {
    eval "$1=\"\$2\""
}
dedup_pathvar () {
    pathvar_name="$1"
    pathvar_value="$(get_var "$pathvar_name")"
    deduped_path="$(perl -e 'print join(":",grep { not $seen{$_}++ } split(/:/, $ARGV[0]))' "$pathvar_value")"
    set_var "$pathvar_name" "$deduped_path"
}
dedup_pathvar PATH
dedup_pathvar MANPATH

Dieser Code dedupliziert sowohl PATH als auch MANPATH und Sie können problemlos dedup_pathvarandere Variablen aufrufen, die durch Doppelpunkte getrennte Pfadlisten enthalten (z. B. PYTHONPATH).

Antwort3

Hier ist ein schickes Exemplar:

printf %s "$PATH" | awk -v RS=: -v ORS=: '!arr[$0]++'

Länger (um zu sehen, wie es funktioniert):

printf %s "$PATH" | awk -v RS=: -v ORS=: '{ if (!arr[$0]++) { print $0 } }'

Ok, da Sie neu bei Linux sind, erfahren Sie hier, wie Sie PATH tatsächlich ohne abschließendes „:“ festlegen.

PATH=`printf %s "$PATH" | awk -v RS=: '{ if (!arr[$0]++) {printf("%s%s",!ln++?"":":",$0)}}'`

Stellen Sie übrigens sicher, dass Ihr PATH KEINE Verzeichnisse mit „:“ enthält, da es sonst zu Problemen kommt.

etwas Anerkennung an:

Antwort4

Solange wir Nicht-AWK-Oneliner hinzufügen:

PATH=$(zsh -fc "typeset -TU P=$PATH p; echo \$P")

(Könnte so einfach sein wie, PATH=$(zsh -fc 'typeset -U path; echo $PATH')aber zsh liest immer mindestens eine zshenvKonfigurationsdatei, die geändert werden kann PATH.)

Es verwendet zwei nette zsh-Funktionen:

  • an Arrays gebundene Skalare ( typeset -T)
  • und Arrays, die doppelte Werte automatisch entfernen ( typeset -U).

verwandte Informationen