web-dev-qa-db-ja.com

bashでディレクトリパスを見つけるときに正規表現を渡す方法は?

anacondaまたはminicondaという名前のディレクトリがユーザー_$HOME_にあるかどうかを確認する小さなbashスクリプトを作成しました。しかし、私の家では_miniconda2_ディレクトリが見つかりません。

どうすれば修正できますか?

_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などです。

14
Jenny

これは、うまく行うには驚くほどトリッキーなことです。

基本的に、_-d_は、正規表現を使用してファイル名を照合できる場合でも、単一の引数のみをテストします。

1つの方法は、問題を反転させ、ディレクトリの正規表現の一致をテストする代わりに、正規表現の一致のディレクトリをテストすることです。言い換えると、単純なシェルグロブを使用して_$HOME_のディレクトリをallでループオーバーし、正規表現に対してそれぞれをテストして、一致を破ります、最後に_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
_

別の方法は、正規表現の代わりに拡張シェルグロブを使用し、配列内のグロブの一致をキャプチャすることです。次に、配列が空でないかどうかをテストします。

_#!/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は、一致がゼロの場合にシェルが一致しない文字列を返すのを防ぎます。


どちらかを再帰的にするには、globstarシェルオプション(_shopt -s globstar_)を設定してから、それぞれ:-

  • (正規表現バージョン):_for d in "$HOME"/**/; do_

  • (拡張グロブバージョン):dirs=( "$HOME"/**/@(ana|mini)conda?([0-9])/ )

13
steeldriver

実際、すでに述べたように、これはトリッキーです。私のアプローチは次のとおりです:

  • findとそのregex機能を使用して、問題のディレクトリを見つけます。
  • 見つかったディレクトリごとにfindxを出力させる
  • xesを文字列に格納する
  • 文字列が空でない場合、ディレクトリの1つが見つかりました。

したがって:

_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_以下のすべてを検索しますが、検索を1レベルに制限します(つまり、サブディレクトリに再帰しません)。
  • _-type d_は、検索をdirectoriesのみに制限します
  • _-regextype egrep_は、findにどのタイプの正規表現を処理するかを指示します。これは、_[0-9]?_や_(…|…)_のようなものが特別であり、findがデフォルトでそれらを認識しないために必要です。
  • -regex "$HOME/(ana|mini)conda[0-9]?"は、実際に必要な正規表現です。
  • _-printf 'x'_は、前の条件を満たすすべてのthingに対してxを出力するだけです。
9
PerlDuck

テストしたいディレクトリ名のリストをループして、それらのいずれかが存在する場合はそれに対処することができます。

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"

このソリューションでは、完全な正規表現の力は明らかに許可されませんが、シェルのグロビングとブレースの拡張は、少なくともあなたが示したケースでは同等です。ループは、1つのディレクトリが存在するとすぐに終了し、以前に設定された変数aの設定を解除します。次のecho行では、 パラメータ展開${a+not }は、aが設定されている(= dirが見つからない)場合は何も展開せず、それ以外の場合は「not」に展開されます。

2
dessert

考えられる回避策は、次に示すように、ミニコンダとアナコンダを別々に検索することです。

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

しかし、誰かが提案を持っている場合、ディレクトリを検索するときになぜ正規表現を渡すことができないのか知りたいのですが。

1
Jenny