在 bash 中查找目录路径时如何传递正则表达式?

在 bash 中查找目录路径时如何传递正则表达式?

我编写了一个小型 bash 脚本来查找我的用户中是否存在名为anaconda或 的目录。但它没有在我的主目录中找到该目录。miniconda$HOMEminiconda2

我该如何修复这个问题?

if [ -d "$HOME"/"(ana|mini)conda[0-9]?" ]; then
    echo "miniconda directory is found in your $HOME"
else
    echo "anaconda/miniconda is not found in your $HOME"
fi

PS:如果我有[ -d "$HOME"/miniconda2 ]; then,那么它会找到 miniconda2 目录,所以我认为错误在于部分"(ana|mini)conda[0-9]?"

我希望脚本具有通用性。对我来说,它是 miniconda2,但对于其他用户来说,它可能是 anaconda2、miniconda3 等等。

答案1

想要做好这件事却出乎意料地困难。

从根本上来说,-d只会测试一个参数——即使您可以使用正则表达式匹配文件名。

一种方法是将问题反过来,测试目录是否与正则表达式匹配,而不是测试目录是否与正则表达式匹配。换句话说,循环全部使用简单的 shell glob中的目录$HOME,并根据正则表达式测试每个目录,匹配时中断,最后测试数组是否BASH_REMATCH非空:

#!/bin/bash

for d in "$HOME"/*/; do
  if [[ $d =~ (ana|mini)conda[0-9]? ]]; then
    break;
  fi
done

if ((${#BASH_REMATCH[@]} > 0)); then
    echo "anaconda/miniconda directory is found in your $HOME"
  else
    echo "anaconda/miniconda is not found in your $HOME"
fi

另一种方法是使用扩展的 shell glob 代替正则表达式,并捕获数组中的任何 glob 匹配项。然后测试数组是否为非空:

#!/bin/bash

shopt -s extglob nullglob

dirs=( "$HOME"/@(ana|mini)conda?([0-9])/ )

if (( ${#dirs[@]} > 0 )); then
  echo "anaconda/miniconda directory is found in your $HOME"
else
  echo "anaconda/miniconda is not found in your $HOME"
fi

尾随/确保仅目录匹配;nullglob防止 shell 在零匹配的情况下返回不匹配的字符串。


要使任一递归,请设置globstarshell 选项(shopt -s globstar),然后分别:-

  • (正则表达式版本):for d in "$HOME"/**/; do

  • (扩展的 glob 版本):dirs=( "$HOME"/**/@(ana|mini)conda?([0-9])/ )

答案2

确实,正如前面提到的,这很棘手。我的方法如下:

  • 使用find及其正则表达式查找相关目录的能力。
  • find打印x每个找到的目录
  • 将 es存储x在字符串中
  • 如果字符串非空,则表示找到了其中一个目录。

因此:

xString=$(find $HOME -maxdepth 1 \
                     -type d \
                     -regextype egrep \
                     -regex "$HOME/(ana|mini)conda[0-9]?" \
                     -printf 'x');
if [ -n "$xString" ]; then
    echo "found one of the directories";
else
    echo "no match.";
fi

解释:

  • find $HOME -maxdepth 1查找下面的所有内容$HOME ,但将搜索限制在一个级别(即:它不会递归到子目录)。
  • -type d限制搜索d范围
  • -regextype egrep告诉find什么类型的正则表达式我们处理。这是必要的,因为像[0-9]?和 这样的东西(…|…)有些特殊,find 默认情况下无法识别它们。
  • -regex "$HOME/(ana|mini)conda[0-9]?"是实际的 正则表达式我们想要关注
  • -printf 'x'只打印x每个事物 满足先前的条件。

答案3

您可以循环遍历要测试的目录名称列表,如果其中一个存在则对其采取行动:

a=0
for i in {ana,mini}conda{,2}; do
  if [ -d "$i" ]; then
    unset a
    break
  fi
done
echo "anaconda/miniconda directory is ${a+not }found in your $HOME"

此解决方案显然无法发挥正则表达式的全部功能,但至少在您展示的情况下,shell 通配符和括号扩展是相等的。只要有一个目录存在,循环就会退出,并取消设置先前设置的变量a。在随后的echo一行中,参数扩展 ${a+not }a如果设置了(=未找到目录),则扩展为无,否则扩展为“不”。

答案4

可能的解决方法是分别搜索 miniconda 和 anaconda,如下所示

if [ -d "$HOME"/miniconda* ] || [ -d "$HOME"/anaconda* ]; then
    echo "miniconda directory is found in your $HOME"
else
    echo "anaconda/miniconda is not found in your $HOME"
fi

但是如果有人有建议,我想知道为什么我们不能在搜索目录时传递正则表达式。

相关内容