shell 检测PATH中是否有特定的目录项

xtfmy6hx  于 2023-01-09  发布在  Shell
关注(0)|答案(9)|浏览(214)

对于/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
fxnxkyjh

fxnxkyjh1#

使用grep是多余的,如果您搜索的内容碰巧包含RE元字符,可能会引起麻烦。这个问题可以使用bash的内置[[命令很好地解决:

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

注意,在$PATH的扩展和要搜索的路径之前添加冒号解决了子字符串匹配问题;双引号路径避免了元字符的麻烦。

2eafrhcq

2eafrhcq2#

绝对没有必要为此使用像grep这样的外部实用程序。下面是我一直在使用的,它应该可以移植回甚至是Bourne shell的遗留版本。

case :$PATH: # notice colons around the value
  in *:$HOME/bin:*) ;; # do nothing, it's there
     *) echo "$HOME/bin not in $PATH" >&2;;
esac
krugob8w

krugob8w3#

下面是不使用grep的方法:

if [[ $PATH == ?(*:)$HOME/bin?(:*) ]]

这里的关键是使用?()结构使冒号和通配符成为可选的,这种形式的元字符应该没有任何问题,但是如果你想包含引号,这就是它们的位置:

if [[ "$PATH" == ?(*:)"$HOME/bin"?(:*) ]]

这是使用match运算符(=~)的另一种方法,因此语法更像grep

if [[ "$PATH" =~ (^|:)"${HOME}/bin"(:|$) ]]
vvppvyoh

vvppvyoh4#

很简单很天真的事:

echo "$PATH"|grep -q whatever && echo "found it"

无论你要找什么,你都可以把$?放进一个变量中,或者使用一个合适的if语句。
局限性包括:

  • 以上代码将匹配较大路径的子字符串(尝试匹配“bin”,它可能会找到它,尽管“bin”不在您的路径中,而/bin和/usr/bin在您的路径中)
  • 以上不会自动展开类似~的快捷键

或者使用perl一行程序:

perl -e 'exit(!(grep(m{^/usr/bin$},split(":", $ENV{PATH}))) > 0)' && echo "found it"

这仍然有一个限制,即它不会执行任何shell扩展,但是如果有一个子字符串匹配,它也不会失败(上面匹配“/usr/bin“,以防这一点不清楚)。

bqujaahr

bqujaahr5#

下面是一个纯粹的bash实现,它不会因为部分匹配而导致误报。

if [[ $PATH =~ ^/usr/sbin:|:/usr/sbin:|:/usr/sbin$ ]] ; then
  do stuff
fi

从3.0版开始,=~操作符使用了bash中提供的正则表达式模式支持。检查了三个模式,由正则表达式的OR操作符|分隔。
所有三个子模式都相对相似,但是它们的差异对于避免部分匹配非常重要。
在正则表达式中,^匹配行首,$匹配行尾。只有当第一个模式查找的路径是$PATH中的第一个值时,第一个模式才会计算为true。只有当第三个模式查找的路径是$PATH中的最后一个值时,第三个模式才会计算为true。当第二个模式找到它要查找的路径时,第二个模式才会计算为true。s查找介于其他值之间的值,因为它查找的是$PATH变量使用的分隔符:,位于所搜索路径的两侧。

gwbalxhn

gwbalxhn6#

我编写了以下shell函数来报告当前PATH中是否列出了某个目录。此函数与POSIX兼容,可以在Dash和Bash等兼容的shell中运行(不依赖于Bash特有的特性)。
它包括将相对路径转换为绝对路径的功能。它使用readlinkrealpath实用程序来完成此操作,但如果提供的目录没有..或其他链接作为其路径的组成部分,则不需要这些工具。除此之外,该函数不需要任何 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
}

使用:$PATH:的部分确保了如果所需路径是PATH中的第一个或最后一个条目,模式也会匹配。

jq6vz3qz

jq6vz3qz7#

这是一种暴力破解的方法,但它在所有情况下都有效,除非路径项包含冒号,并且除了shell之外不使用其他程序。

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
whlutmcx

whlutmcx8#

$PATH是以:分隔的字符串列表,用于描述目录列表。目录是以/分隔的字符串列表。两个不同的字符串可以指向同一目录(如$HOME~,或者/usr/local/bin/usr/local/bin/)。所以我们必须修正我们要比较/检查的规则。我建议比较/检查整个字符串,而不是物理目录,但是去除重复的和尾随的/
首先从$PATH中删除重复和尾随的/

echo $PATH | tr -s / | sed 's/\/:/:/g;s/:/\n/g'

现在假设$d包含您要检查的目录,然后通过管道传输前面的命令来检查$PATH中的$d

echo $PATH | tr -s / | sed 's/\/:/:/g;s/:/\n/g' | grep -q "^$d$" || echo "missing $d"
bvjveswy

bvjveswy9#

更好更快的解决方案是:

DIR=/usr/bin
[[ " ${PATH//:/ } " =~ " $DIR " ]] && echo Found it || echo Not found

我个人在我的bash提示符中使用它来在我转到$PATH中的目录时添加图标。

相关问题