С /bin/bash
, как бы определить, есть ли у пользователя определенный каталог в переменной $PATH?
Например
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
С /bin/bash
, как бы определить, есть ли у пользователя определенный каталог в переменной $PATH?
Например
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
Что-то действительно простое и наивное:
echo "$PATH"|grep -q whatever && echo "found it"
Где то, что вы ищете. Вместо &&
вы можете поместить $?
в переменную или использовать правильный оператор if
.
Ограничения включают:
Или используя однострочный perl:
perl -e 'exit(!(grep(m{^/usr/bin$},split(":", $ENV{PATH}))) > 0)' && echo "found it"
У этого все еще есть ограничение на то, что он не будет выполнять каких-либо расширений оболочки, но это не сработает, если подстрока совпадает. (Вышеуказанные совпадения "/usr/bin
", если это не ясно).
Использование grep
является излишним и может вызвать проблемы, если вы ищете что-либо, что включает метасимволы RE. Эта проблема может быть решена с помощью команды bash builtin [[
:
if [[ ":$PATH:" == *":$HOME/bin:"* ]]; then
...
Обратите внимание, что добавление двоеточий перед расширением $PATH и пути для поиска разрешает проблему соответствия подстроки; двойное цитирование пути позволяет избежать проблем с метасимволами.
Вот как это сделать без grep
:
if [[ $PATH == ?(*:)$HOME/bin?(:*) ]]
Ключ здесь состоит в том, чтобы сделать colons и wildcards необязательными, используя конструкцию ?()
. Там не должно быть никаких проблем с метасимволами в этой форме, но если вы хотите включить кавычки, это куда они идут:
if [[ "$PATH" == ?(*:)"$HOME/bin"?(:*) ]]
Это другой способ сделать это с помощью оператора соответствия (=~
), поэтому синтаксис больше похож на grep
's:
if [[ "$PATH" =~ (^|:)"${HOME}/bin"(:|$) ]]
$PATH
- список строк, разделенных символом :
, которые описывают список каталогов. Каталог представляет собой список строк, разделенных символом /
. Две разные строки могут указывать на один и тот же каталог (например, $HOME
и ~
, или /usr/local/bin
и /usr/local/bin/
). Поэтому мы должны исправить правила того, что мы хотим сравнить/проверить. Я предлагаю сравнивать/проверять целые строки, а не физические каталоги, но удалять дубликаты и завершать /
.
Сначала удалите дубликат и конец /
из $PATH
:
echo $PATH | tr -s / | sed 's/\/:/:/g;s/:/\n/g'
Теперь предположим, что $d
содержит каталог, который вы хотите проверить. Затем подключите предыдущую команду, чтобы проверить $d
на $PATH
.
echo $PATH | tr -s / | sed 's/\/:/:/g;s/:/\n/g' | grep -q "^$d$" || echo "missing $d"
Я написал следующую функцию оболочки, чтобы сообщить, указан ли каталог в текущем PATH
. Эта функция совместима с POSIX и будет работать в совместимых оболочках, таких как Dash и Bash (не полагаясь на Bash -специфические функции).
Он включает в себя функции для преобразования относительного пути к абсолютному пути. Для этого используются служебные программы readlink
или realpath
, но эти инструменты не нужны, если в поставляемом каталоге нет ..
или других ссылок в качестве компонентов его пути. Помимо этого, функция не требует каких-либо программ, внешних по отношению к оболочке.
# 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
}
Часть с использованием :$PATH:
гарантирует, что шаблон также будет соответствовать, если желаемый путь является первой или последней записью в PATH
. Этот умный трюк основан на этом ответе Гленна Джекмана на Unix и Linux.