對於/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"
這仍然有限制,它不會做任何shell擴展,但它不會失敗,如果子字符串匹配。 (以上匹配「/usr/bin
」,如果不清楚的話)。
使用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的兩膨脹和搜索路徑之前添加冒號解決了子字符串匹配問題;雙引號路徑避免了元字符的問題。
如果'$ HOME/bin'在'$ PATH'的開頭或末尾,那末在每一端都不可能有冒號。 – 2009-09-09 04:44:40
我不確定我是否理解你的反對意見。例如,如果$ PATH是/ usr/bin:/ bin:/ usr/sbin:/ sbin:/ home/fred/bin,那麼「:/ usr/bin:/ bin:/ usr/sbin:/ sbin:/ home/fred/bin:「會匹配*」:/ home/fred/bin:「*就好了。 – 2009-09-09 07:18:57
你說得對。我沒有看到「$ PATH」附近冒號的作用。抱歉。 – 2009-09-09 13:56:50
這裏是如何做到這一點不grep
:
if [[ $PATH == ?(*:)$HOME/bin?(:*) ]]
的這裏關鍵是使冒號和使用?()
結構通配符可選。不應該有在這種形式的元字符的任何問題,但如果你希望包括引號,這是他們到何處去:
if [[ "$PATH" == ?(*:)"$HOME/bin"?(:*) ]]
這是另一種方式來做到這一點使用匹配運算符(=~
)這樣的語法更像是grep
的:
if [[ "$PATH" =~ (^|:)"${HOME}/bin"(:|$) ]]
'?(:*)'是一個[擴展glob](https://mywiki.wooledge.org/glob#extglob)模式,需要在大多數平臺上分別明確啓用('shopt -s extglob')。 – tripleee 2018-01-10 11:09:15
$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"
我寫了下面的shell功能,如果一個目錄在當前PATH
上市報告。這個函數是POSIX兼容的,並且可以在Dash和Bash等兼容的shell中運行(不依賴於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
第一或最後一個條目。這個巧妙的技巧是基於this answer by Glenn Jackman on Unix & Linux。
絕對沒有必要使用像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
在JasonWoof的回答中匹配到行首和冒號的開始/結尾處理您的子字符串匹配限制。 Tilde擴展不是一個常見問題,因爲大多數人在分配時允許擴展它(例如'PATH =「〜/ bin:$ PATH」'),但如果需要可以用替換來處理。 – Cascabel 2009-09-08 21:33:31
不錯,有人在3.5年後低估了這一點。並沒有留下評論。瘸。 – 2013-03-29 16:04:47
我正在使用grep解決方案用冒號包裝模式。 – elias 2015-03-09 17:44:12