检测用户的path中是否有特定的目录

使用/bin/bash ,我将如何检测用户是否在其$ PATHvariables中有特定的目录?

例如

 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" 

无论你在寻找什么。 而不是&&你可以把$? 变成一个variables或使用一个适当的if语句。

限制包括:

  • 以上将匹配较大path的子串(尽pipe“bin”不在你的path中,/ bin和/ usr / bin都是这样的),尝试在“bin”上匹配,它可能会find它。
  • 以上不会自动扩展〜的快捷方式

或者使用perl单行程式:

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

这仍然有限制,它不会做任何shell扩展,但它不会失败,如果一个子string匹配。 (如果不清楚,以上匹配“ /usr/bin ”)。

使用grep是矫枉过正的,如果你正在寻找包含RE元字符的东西,会造成麻烦。 这个问题可以用bash的builtin很好的解决[[ command:

 if [[ ":$PATH:" == *":$HOME/bin:"* ]]; then ... 

请注意,在$ PATH扩展和searchpath之前添加冒号解决了子string匹配问题; 双引号的path避免了元字符的麻烦。

这里是如何做到这一点,没有grep

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

这里的关键是使用?()构造使冒号和通配符可选。 在这种forms中元字符不应该有任何问题,但是如果你想包含引号,这是他们去的地方:

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

这是另一种使用匹配运算符( =~ )的方法,所以语法更像grep

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

$PATH是由:分隔的string列表:描述目录列表。 目录是由/分隔的string列表。 两个不同的string可能指向相同的目录(如$HOME~ ,或/usr/local/bin/usr/local/bin/ )。 所以我们必须修正我们想要比较/检查的规则。 我build议比较/检查整个string,而不是物理目录,但删除重复和尾随/

首先删除$PATH中的重复和尾随:

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

现在假设$d包含你想检查的目录。 然后通过pipe道命令来检查$PATH $d

 echo $ PATH |  tr -s / |  sed的/ \ /:/:/ g; s /:/ \ n / g'|  grep -q“^ $ d $”|| 回声“缺less$ d”

我编写了下面的shell函数来报告目录是否在当前PATH列出。 这个函数是POSIX兼容的,并且可以在Dash和Bash等兼容的shell中运行(不依赖于Bash特有的特性)。

它包括将相对path转换为绝对path的function。 它使用readlinkrealpath实用工具,但如果提供的目录没有..或其他链接作为其path的组件,则不需要这些工具。 除此之外,该function不需要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:如果所需的path是PATH的第一个或最后一个条目,则确保该模式也匹配。 这个聪明的窍门是基于Unix和Linux上Glenn Jackman的这个回答 。