Wie würde ich mit /bin/bash
feststellen, ob ein Benutzer ein bestimmtes Verzeichnis in seiner $ PATH-Variablen hat?
Zum Beispiel
if [ -p "$HOME/bin" ]; then
echo "Your path is missing ~/bin, you might want to add it."
else
echo "Your path is correctly set"
fi
Etwas wirklich einfaches und naives:
echo "$PATH"|grep -q whatever && echo "found it"
Wo auch immer das ist, wonach Sie suchen. Anstelle von &&
können Sie $?
in eine Variable einfügen oder eine korrekte if
-Anweisung verwenden.
Einschränkungen sind:
Oder mit einem Perl-One-Liner:
Perl -e 'exit(!(grep(m{^/usr/bin$},split(":", $ENV{PATH}))) > 0)' && echo "found it"
Das hat immer noch die Einschränkung, dass es keine Shell-Erweiterungen ausführt, aber es scheitert nicht, wenn eine Teilzeichenfolge übereinstimmt. (Das obige stimmt mit "/usr/bin
" überein, falls das nicht klar war).
Die Verwendung von grep
ist übertrieben und kann zu Problemen führen, wenn Sie nach etwas suchen, das RE-Metazeichen enthält. Dieses Problem lässt sich mit dem [[
-Befehl von bash perfekt lösen:
if [[ ":$PATH:" == *":$HOME/bin:"* ]]; then
echo "Your path is correctly set"
else
echo "Your path is missing ~/bin, you might want to add it."
fi
Beachten Sie, dass das Hinzufügen von Doppelpunkten vor der Erweiterung von $ PATH und dem Pfad, nach dem gesucht werden soll, das Problem der Übereinstimmung der Teilzeichenfolge löst. Wenn Sie den Pfad doppelt zitieren, werden Probleme mit Metazeichen vermieden.
So geht es ohne grep
:
if [[ $PATH == ?(*:)$HOME/bin?(:*) ]]
Der Schlüssel hier ist, die Doppelpunkte und Platzhalterzeichen mithilfe des Konstrukts ?()
optional zu machen. Es sollte kein Problem mit Metazeichen in diesem Formular geben, aber wenn Sie Anführungszeichen hinzufügen möchten, gehen sie hier hin:
if [[ "$PATH" == ?(*:)"$HOME/bin"?(:*) ]]
Dies ist eine andere Möglichkeit, dies mit dem Übereinstimmungsoperator (=~
) zu tun, sodass die Syntax eher der von grep
entspricht:
if [[ "$PATH" =~ (^|:)"${HOME}/bin"(:|$) ]]
Es ist absolut nicht notwendig, externe Dienstprogramme wie grep
zu verwenden. Hier ist, was ich verwendet habe, was auch auf ältere Versionen der Bourne Shell portierbar sein sollte.
case :$PATH: # notice colons around the value
in *:$HOME/bin:*) ;; # do nothing, it's there
*) echo "$HOME/bin not in $PATH" >&2;;
esac
Ich habe die folgende Shell-Funktion geschrieben, um zu berichten, ob ein Verzeichnis im aktuellen PATH
aufgeführt ist. Diese Funktion ist POSIX-kompatibel und kann in kompatiblen Shells wie Dash und Bash ausgeführt werden (ohne sich auf Bash-spezifische Funktionen zu verlassen).
Es enthält Funktionen zum Konvertieren eines relativen Pfads in einen absoluten Pfad. Dazu werden die Dienstprogramme readlink
oder realpath
verwendet. Diese Tools werden jedoch nicht benötigt, wenn das angegebene Verzeichnis ..
oder andere Links nicht als Komponenten seines Pfads enthält. Ansonsten benötigt die Funktion keine Programme außerhalb der Shell.
# Check that the specified directory exists – and is in the PATH.
is_dir_in_path()
{
if [ -z "${1:-}" ]; then
printf "The path to a directory must be provided as an argument.\n" >&2
return 1
fi
# Check that the specified path is a directory that exists.
if ! [ -d "$1" ]; then
printf "Error: ‘%s’ is not a directory.\n" "$1" >&2
return 1
fi
# Use absolute path for the directory if a relative path was specified.
if command -v readlink >/dev/null ; then
dir="$(readlink -f "$1")"
Elif command -v realpath >/dev/null ; then
dir="$(realpath "$1")"
else
case "$1" in
/*)
# The path of the provided directory is already absolute.
dir="$1"
;;
*)
# Prepend the path of the current directory.
dir="$PWD/$1"
;;
esac
printf "Warning: neither ‘readlink’ nor ‘realpath’ are available.\n"
printf "Ensure that the specified directory does not contain ‘..’ in its path.\n"
fi
# Check that dir is in the user’s PATH.
case ":$PATH:" in
*:"$dir":*)
printf "‘%s’ is in the PATH.\n" "$dir"
return 0
;;
*)
printf "‘%s’ is not in the PATH.\n" "$dir"
return 1
;;
esac
}
Der Teil, der :$PATH:
verwendet, stellt sicher, dass das Muster auch übereinstimmt, wenn der gewünschte Pfad der erste oder letzte Eintrag in PATH
ist. Dieser clevere Trick basiert auf dieser Antwort von Glenn Jackman auf Unix & Linux .
$PATH
ist eine Liste von Strings, die durch :
getrennt sind und eine Liste von Verzeichnissen beschreiben. Ein Verzeichnis ist eine Liste von Zeichenfolgen, die durch /
getrennt sind. Zwei verschiedene Zeichenfolgen können auf dasselbe Verzeichnis verweisen (wie $HOME
und ~
oder /usr/local/bin
und /usr/local/bin/
). Also müssen wir die Regeln für das, was wir vergleichen wollen, festlegen. Ich schlage vor, die gesamten Zeichenfolgen und nicht physische Verzeichnisse zu vergleichen/zu prüfen, aber doppelte und nachgestellte /
zu entfernen.
Entfernen Sie zuerst das doppelte und nachfolgende /
von $PATH
:
echo $ PATH | tr -s/| sed 's/\ /: /:/g; s /:/\ n/g'
Angenommen, $d
enthält das Verzeichnis, das Sie überprüfen möchten. Dann den vorherigen Befehl weiterleiten, um $d
in $PATH
zu überprüfen.
echo $ PATH | tr -s/| sed 's/\ /: /:/g; s /:/\ n/g' | grep -q "^ $ d $" || echo "fehlt $ d"
Dies ist eine Brute-Force-Methode, sie funktioniert jedoch in allen Fällen, außer wenn ein Pfadeintrag einen Doppelpunkt enthält. Es werden keine anderen Programme als die Shell verwendet.
previous_IFS=$IFS
dir_in_path='no'
export IFS=":"
for p in $PATH
do
[ "$p" = "/path/to/check" ] && dir_in_path='yes'
done
[ "$dir_in_path" = "no" ] && export PATH="$PATH:/path/to/check"
export IFS=$previous_IFS