如何检查 $PWD 是否是给定路径的子目录

Tob*_*ler 34 shell bash directory string

例如检查是否$PWD是/home 的子目录。换句话说,我正在寻找一个 bash 字符串操作来检查一个字符串是否以另一个字符串开头。

Gil*_*il' 45

在任何 Bourne 风格的 shell 中测试一个字符串是否是另一个字符串的前缀:

case $PWD/ in
  /home/*) echo "home sweet home";;
  *) echo "away from home";;
esac
Run Code Online (Sandbox Code Playgroud)

相同的原理适用于后缀或子字符串测试。请注意,case构造与文件名不同,它*匹配任何字符,包括 a/或首字母..

在实现[[ … ]]语法(即 bash、ksh 和 zsh)的shell 中,它可用于将字符串与模式匹配。(请注意,该[命令只能测试字符串的相等性。)

if [[ $PWD/ = /home/* ]]; then …
Run Code Online (Sandbox Code Playgroud)

如果您专门测试当前目录是否在 下/home,由于符号链接的原因,简单的子字符串测试是不够的。

如果/home是它自己的文件系统,则测试当前目录 ( .) 是否在该文件系统上。

if [ "$(df -P . | awk 'NR==2 {print $6}')" = "/home" ]; then
  echo 'The current directory is on the /home filesystem'
fi
Run Code Online (Sandbox Code Playgroud)

如果您有 NetBSD、OpenBSD 或 GNU(即 Linux)readlink,您可以使用readlink -f从路径中去除符号链接。

case $(readlink -f .)/ in $(readlink -f /home)/*) …
Run Code Online (Sandbox Code Playgroud)

否则,您可以使用pwd来显示当前目录。但是,如果您的 shell 跟踪cd命令并保留用于访问目录的名称而不是其“实际”位置,则您必须注意不要使用内置的 shell 。

case $(pwd -P 2>/dev/null || env PWD= pwd)/ in
  "$(cd /home && { pwd -P 2>/dev/null || env PWD= pwd; })"/*) …
Run Code Online (Sandbox Code Playgroud)


Jan*_*der 32

如果您想可靠地测试一个目录是否是另一个目录的子目录,您需要的不仅仅是字符串前缀检查。Gilles 的回答详细描述了如何正确进行此测试。

但是如果你确实想要一个简单的字符串前缀检查(也许你已经规范了你的路径?),这是一个很好的方法:

test "${PWD##/home/}" != "${PWD}"
Run Code Online (Sandbox Code Playgroud)

如果$PWD以 "/home/" 开头,它会在左侧被剥离,这意味着它不会与右侧匹配,因此 "!=" 返回 true。

  • +1 完美,对于更一般的情况:`[ "${PWD##$VAR}" != "$PWD" ]` 如果这是一个 [code-golf ](http://stackoverflow.com/问题/标记/代码高尔夫)问题你会用两个字符击败我;-) 而且它看起来更易读...... (3认同)

Tob*_*ler 10

粗版:

[ ${PWD:0:6} = "/home/" ]
Run Code Online (Sandbox Code Playgroud)

的缺点在于,人们必须先算个字符,没有人可以替代/home/的东西一般喜欢$1

编辑(感谢@Michael)用于与$VAR可以使用的比较的概括

[ "${PWD:0:${#VAR}}" = $VAR ]
Run Code Online (Sandbox Code Playgroud)

  • `${#var}` 是 `$var` 的长度,因此您可以将其概括为 `[ "${PWD:0:${#1}}" = "$1" ]` (4认同)

小智 6

您可以将 gnurealpath与 --relative-to 或 --relative-base 参数结合使用,并结合字符串检查

$ mkdir -p /tmp/a/b/c/d /tmp/a/e/f
$ isSubPath() if [[ $(realpath --relative-base="$1" -- "$2")  =~ ^/ ]]
    then printf '%s\n' "$2 NOT subpath of $1"
    else printf '%s\n' "$2 subpath of $1"
  fi
$ isSubPath /tmp/a/ /tmp/a/e/
/tmp/a/e/ subpath of /tmp/a/
$ isSubPath /tmp/a/ /tmp/a/e/f/
/tmp/a/e/f/ subpath of /tmp/a/
$ isSubPath /tmp/a/b/ /tmp/a/e/f/
/tmp/a/e/f/ NOT subpath of /tmp/a/b/
$ cd /tmp/a/b/c/d/
$ isSubPath . /tmp/a/
/tmp/a/ NOT subpath of .
$ isSubPath /tmp/a/ .
. subpath of /tmp/a/
$ isSubPath /tmp/a/ ../../../
../../../ subpath of /tmp/a
$ isSubPath /tmp/a/ ../../../../../../
../../../../../../ NOT subpath of /tmp/a/
$ isSubPath /tmp/a/ ../../../../../../tmp/a/e/
../../../../../../tmp/a/e/ subpath of /tmp/a/
Run Code Online (Sandbox Code Playgroud)