以下の例は問題を説明しています。置換を使用すると、エコーされてパターンとして認識されたときに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
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
)、しかしここでは、それは一度は望ましい動作です。