web-dev-qa-db-ja.com

shopt -s nullglobが配列要素の疑問符付きの文字列を削除するのはなぜですか?

この小さな設定は私を夢中にさせました:

shopt -s nullglob

私はbash4.3スクリプトでそれをグローバル設定として使用します 空のディレクトリのスキャンエラーを回避します

今、私は理解できない奇妙な問題を見つけました:

# shopt -s nullglob
# array=(foo bar)
# echo "${array[@]}"
foo bar
# array=(foo bar?)
# echo "${array[@]}"
foo
# shopt -u nullglob
# array=(foo bar)
# echo "${array[@]}"
foo bar
# array=(foo bar?)
# echo "${array[@]}"
foo bar?

ご覧のとおり、配列要素からbar?が削除されますが、なぜですか? documentation は、*?を含む可能性のあるファイル名パターンを指しますが、配列だけでは「ファイルが一致しない」とは関係ありません。

If set, Bash allows filename patterns which match no files to expand to a null string, rather than themselves.

これはバグですか?

P.S.問題を解決するために、ループの周りにnullglobを設定/設定解除します。これは問題ではありません!

Update1

@MichaelHomerが求めたように:

# shopt -s nullglob
# array=(*)
# echo "${array[@]}"
1 Video_folder Server bin config dev etc etc.defaults initrd lib lib32 lib64 lost+found mnt proc root run sbin storage sys tmp tmpRoot usr var var.defaults volume1
# shopt -u nullglob
# array=(*)
# echo "${array[@]}"
1 Video_folder Server bin config dev etc etc.defaults initrd lib lib32 lib64 lost+found mnt proc root run sbin storage sys tmp tmpRoot usr var var.defaults volume1

そしてこれはどういう意味ですか?

1
mgutt

array=(foo bar?)を実行すると、_bar?_文字列は引用符で囲まれず、ファイル名グロブ文字_?_(任意の1文字に一致)が含まれます。これは、シェルがこの値に対してファイル名のグロブを実行することを意味します。パターンが何にも一致しない場合、デフォルトではそのままになります。何か(_bar1_、_bar-_、_bar._など)と一致する場合、一致する名前が配列に挿入されます。

nullglobを有効にすると、引用符で囲まれていないグロブパターン_bar?_は、それに一致するファイル名がない場合は完全に削除されます(これが、通常、nullglobを有効にする理由です)。これは、この場合、配列にはfoo要素のみが含まれることを意味します。

言い換えると、nullglob設定は(現在のディレクトリに_bar?_というファイルがない限り)引用符で囲まれていないWord _bar?_が配列の要素として割り当てられるのを防ぎます。

配列に2つの文字列fooと_bar?_が必要な場合の解決策は、それらを引用符で囲むことです(fooは引用符で囲む必要はありませんが、一貫性を保つのに問題はありません)。 :

_array=('foo' 'bar?')
_

これを「解決」する別の方法は、disableファイル名のグロブです。これは_set -f_を介して行われます:

_set -f
array=(foo bar?)
set +f
_

Michaelがおそらくarray=(*)で示したかったのは、引用符で囲まれていない値(ここでは引用符で囲まれていない_*_)に対してグロブが発生することです。これがあなたの問題の根源であるため、彼はこれを示したかったのです。

3
Kusalananda