スクリプトでglobを使用してサブディレクトリがあることを確認する

スクリプトでglobを使用してサブディレクトリがあることを確認する

bin時々変更されるディレクトリ内にディレクトリがあるかどうかを確認しようとしています。この特別なケースでは、Rubyのバージョン番号が変更されることがあります(例$HOME/.gem/ruby/2.6.0/bin:)。これまで私がしたことは次のとおりです。

#!/usr/bin/env zsh
ruby_gem_home="$HOME/.gem/ruby/*/bin"
if [[ -d $ruby_gem_home ]]; then
  echo "The ruby gems directory exists!"
else
  echo "Ruby gems directory missing!"
fi

findこれはログインプロセスの一部なので、使用したくありません。組み込みのzsh / bashコマンドを使用してこれを達成する最もエレガントな方法は何ですか?

ありがとうございます!

編集する:これがスクリプトであることを忘れましたzsh

答え1

特にこの状況について

ディレクトリの検索には意味がないと思います。インストールされているRubyのバージョンと一致しないディレクトリを使用するのはなぜですか?ユーザーが別のディレクトリを設定した場合はどうなりますか~/.gemrc

私はRubyに精通していませんが、正しい解決策はgempath

ruby_gem_home=$(gem environment gempath | sed 's/:.*//')
if [ -z "$ruby_gem_home" ]; then unset ruby_gem_home; fi

zshから

function set_ruby_gem_home {
  emulate -LR zsh
  local dirs
  dirs=($HOME/.gem/ruby/*/bin(NnOn))
  if (($#dirs == 0)); then
    unset ruby_gem_home
  else
    ruby_gem_home=$dirs[0]
  fi
}

これグローバル予選 N不一致が原因でエラーが発生するのではなく、結果が空の配列であることを確認してください。 glob修飾子を使用nしてOnバージョン番号を減らしてリストを並べ替えます。一致する項目が複数ある場合は、別の項目を選択するにはこのオプションを調整してください。

バッシュから:

function set_ruby_gem_home {
  local dirs
  dirs=(~/.gem/ruby/*/bin(NnOn))
  if (($#dirs == 0)); then
    unset ruby_gem_home
  else
    ruby_gem_home=$dirs[0]
  fi
}

バッシュから

function set_ruby_gem_home {
  local dirs restore_options
  restore_options=$(setopt +o)
  shopt -s nullglob
  dirs=(~/.gem/ruby/*/bin)
  if (($#dirs == 0)); then
    unset ruby_gem_home
  else
    ruby_gem_home=${dirs[${#dirs[@]}-1]}
  fi
  eval "$restore_options"
}

ここでは通常、常に最新バージョンではありませんが、最後の配列要素を使用します。10sorted before 9

答え2

配列を使用して、配列の最初の要素(bashの場合は[0]、zshの場合は[1])がディレクトリであることを確認してください。たとえば、次のようになりますbash

# the trailing slash in "$HOME"/.gem/ruby/*/bin/ ensures that
# the glob matches only directories.
rubygemdirs=( "$HOME"/.gem/ruby/*/bin/ )

if [ -d "${rubygemdirs[0]}" ] ; then
   echo "At least one ruby gem dir exists"
else
   echo "No ruby gem dirs were found"
fi

zshタスクを実行する前に、bash現在実行中のシェルを探す必要があります。これは、配列の最初のインデックスがある0かどうかを示します1。また(N)、globに一致するものがない場合は、zshが終了しないようにglobと一緒に使用する必要があるかどうかを判断します(globがエラーと一致すると、zshはデフォルトで終了します)。

(この時点で安定して動作するスクリプトを書くことが明らかになり始める必要があります。両方bashとzshはおそらく貴重なものよりも多くの問題があるでしょう)

if [ -n "$BASH_VERSION" ] ; then
   first_idx=0
   rubygemdirs=( "$HOME"/.gem/ruby/*/bin/ )
elif [ -n "$ZSH_VERSION"  ] ; then
   first_idx=1
   emulate sh
   rubygemdirs=( "$HOME"/.gem/ruby/*/bin/ )
   emulate zsh
fi

if [ -d "${rubygemdirs[$first_idx]}" ] ; then
...

必要に応じて配列を繰り返して、要素が特定のバージョンと一致することを確認することもできます。例えば

for d in "${rubygemdirs[@]}" ; do
  [[ $d =~ /2\.6\.0/ ]] && echo found gem dir for ruby 2.6.0
done

注:/正規表現のsは文字通りスラッシュです。のように正規表現の始まりと終わりを表示しませんsed

答え3

ワイルドカードはリストコンテキストでのみ拡張されます。つまり、複数のコンテンツに拡張できます。スカラー変数に割り当てると、スカラー変数は1つの値しか保持できないため、拡張できません。

を使用すると、リストコンテキストでglobが拡張されているファイルリストではなく、文字列をスカラー変数に保存するだけですruby_gem_home="$HOME/.gem/ruby/*/bin"/home/user/.gem/ruby/*/bin$ruby_gem_home

for/select x inzshのリストコンテキストは、リダイレクトターゲット(multios開いたとき)、配列または関連配列の割り当て、および他のいくつかのケースでは、単純なコマンドまたは匿名関数の引数にすることができます。

ここでは匿名関数を使用できます。

() {
  unset ruby_gem_home
  case $# in
    (0) print -u2 "Ruby gems directory missing!";;
    (1) print -u2 "The ruby gems directory exists!"
        ruby_gem_home=$1;;
    (*) print -u2 "More than one ruby gem directory, don't know which to choose!";;
  esac
} ~/.gem/ruby/*/bin(N-/)

Nglob修飾子は、一致がない場合にエラーを報告するのではなく、globが空のリストに展開され、-/ファイル形式に制限されるようにここに追加されます。目次(シンボリックリンク解決後に決定-

Ruby gem ディレクトリが複数あり、バージョン番号が最も高いディレクトリを選択するには、次の手順を実行します。

() {
  unset ruby_gem_home
  case $# in
    (0) print -u2 "Ruby gems directory missing!";;
    (1) print -u2 "The ruby gems directory exists!"
        ruby_gem_home=$1;;
    (*) print -ru2 "More than one ruby gem directory, picking $1!"
        ruby_gem_home=$1;;
  esac
} ~/.gem/ruby/*/bin(N-/nOn)

ame によって逆順に開いてソートされるので、n最も高い数値を持つものが含まれます。numericglobsortOn on$1


1 説明のとおりinfo zsh 'Conditional Expressions'、特別な場合もあります。このextendedglobオプションがオンの場合、[[ ... ]]通常は-n/-z演算子を使用して内部でglobを使用できます。したがって、[[ -n ~/.gem/ruby/*/bin(#qN-/) ]]ここでそのようなディレクトリが1つ以上あることを確認するために使用できます。

関連情報