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 awk
Befehls möglich ist, aber ich kann nicht herausfinden, wie das geht. Weiß jemand, wie das geht?
Antwort1
Wenn Sie noch keine Duplikate darin haben PATH
und 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_pathvar
andere 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 zshenv
Konfigurationsdatei, 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
).