スペースを含むパスのグローバルマッチ数をどのように簡単に計算できますか?

スペースを含むパスのグローバルマッチ数をどのように簡単に計算できますか?

私は空白のあるパスを扱っています。

私はこのようにグローブを行います(2行目はグローブを設定します):

IFS=$'\n'

VAR="$1/"name_*

for file in $VAR; do
  echo $file
  grep ITEM "$file" | wc -l
done

ここで設定した値を使用すると、ファイル名のスペースでエラーが発生するのを防ぐことができ、ファイルを正しく表示できname_*ます$1IFSfor

しかし今では、globと一致するファイルの総数を取得する簡単な方法が必要です。 forループでカウンタを使用できることはわかっていますが、パイプを使用してこれを行うことができたらと思いますVAR

ただしecho $VAR、グローブを正常に実行しましたが、別のパスが空白になっている場合は、もはやアイテムを分割できないため、問題が発生します。IFSの仕組みなど、この動作をオーバーライドする方法はありますかfor

答え1

必要なものが区切り値のリストである場合は、文字列の使用/拡張を避ける必要があります。

基本的な解決策は、位置パラメータを設定することです。

set -- "$1"/name_*

スペースや改行文字(または他のほとんどの文字)があっても、一致する各ファイルを別々の場所引数として保持します。

shopt -s failglobbashでは、glob()がどのファイルとも一致しない場合、またはglobがどのファイルとも一致できず、結果が得られたくない場合(ただしglob自体ではない)、スクリプトを停止するように設定する必要があります。スクリプトが停止しないようにするには、FAILGlobを設定しないでください。*shopt -s nullglob"$1"/name_*

ファイル数(glob の一致数を計算します。)今簡単に:

echo "$#"

位置パラメーターの数。

forループは次のように減ります。

for file
do  echo "$file"
done

これにより、完全に分割される問題が回避されますIFS

$1コードの挿入を防ぐには、外部値を引用する必要があります。
echo "$file"引用しなければならない。

配列にリストを割り当てることも可能です。

files=( "$1"/name_* )

これにより、位置パラメータが壊れるのを防ぎますが、構文がより複雑になります。配列の要素数は次のとおりです。

echo "${#files[@]}"

ループにはいくつかの変更が必要です。

for file in "${files[@]}"; do
    echo "$file"
done

答え2

スペースの問題を解決できます。そして配列の使用に切り替えると、カウントが取得されます。

VAR=("$1/"name_*) # make array of filenames matching glob

echo "${#VAR[@]}" # number of elements in array

for file in "${VAR[@]}"; do  # loop over individual elements of array
  echo "$file"
  grep ITEM "$file" -c  # grep can count, wc isn't needed
done

関連情報