web-dev-qa-db-ja.com

グロブパターンから定義された変数によるバッシュ置換

以下の例は問題を説明しています。置換を使用すると、エコーされてパターンとして認識されたときにFILENAMEが正しく印刷されるのはなぜですか?

#!/bin/bash

FILEPATH_WITH_GLOB="/home/user/file_*"
FILENAME=$(basename "$FILEPATH_WITH_GLOB")
echo $FILENAME                #file_1234
echo ${FILENAME:1:5}          #ile_*   <---why is this not ile_1
10
FILEPATH_WITH_GLOB="/home/user/file_*"

現在、FILEPATH_WITH_GLOBには/home/user/file_*が含まれています

FILENAME=$(basename "$FILEPATH_WITH_GLOB")

FILENAMEにはfile_*が含まれています。

echo $FILENAME                #file_1234

$FILENAMEはリストコンテキストで引用符で囲まれていないため、その展開ではsplit + glob演算子が実行されるため、一致するファイルのリストに展開されます:filename generationパラメータ展開時に実行されます。

echo ${FILENAME:1:5}          #ile_*   <---why is this not ile_1

リストコンテキストではまだ引用符で囲まれていないパラメーター展開であるため、split + globが実行されます。ただし、ここでは、ile_*パターンはどのファイルとも一致しないため、代わりにそれ自体に展開されます。

ここでおそらく必要なのは:

shopt -s nullglob # have globs expand to nothing when they don't match
set -- /home/user/file_* # expand that pattern into the list of matching 
                         # files in $1, $2...
for file do  # loop over them
  filename=$(basename -- "$file")
  printf '%s\n' "$filename" "${filename:1:5}"
done

または、配列に保存することもできます。

shopt -s nullglob
files=(/home/user/file_*)

最初の一致のみに関心がある場合、または一致が1つしかないことがわかっている場合は、そのファイルを$filesとして参照できます。 bashには通常、配列のすべての要素ではなく$files${files[0]}に展開されるという厄介な動作があります(kshから継承された動作で、zsh)、しかしここでは、それは一度は望ましい動作です。

15