extglob
複合複合内でシェルオプションを設定すると、将来のglob拡張が失敗することがわかりました。複合コマンドの外部でシェルオプションを設定する必要がありますか? Bashのマニュアルページにはそのような要件はありません。
たとえば、次のスクリプトは正しく機能します(印刷a.0 a.1
)。
#!/bin/bash
touch a.0 a.1 \
a.b.0 a.b.1
shopt -s extglob
ls "a."!(b*)
ただし、最後の2行を複合コマンドとして実行すると、次のエラーでスクリプトが失敗します。
syntax error near unexpected token `('
` ls "a."!(b*)'
これはBashバージョン4.2〜4.4とさまざまなバージョンを使用しています。複合コマンド:
(1) 条件付—if
#!/bin/bash
touch a.0 a.1 \
a.b.0 a.b.1
if true; then
shopt -s extglob
ls "a."!(b*)
fi
(2) 校正器 -{ }
#!/bin/bash
touch a.0 a.1 \
a.b.0 a.b.1
{
shopt -s extglob
ls "a."!(b*)
}
(3) サブシェル-- ( )
:
#!/bin/bash
touch a.0 a.1 \
a.b.0 a.b.1
(
shopt -s extglob
ls "a."!(b*)
)
すべてのケースでshopt
複合コマンドの外に移動すると、スクリプトは成功します。
答え1
コマンド全体が解析されるまで、複合コマンドのどの部分も実行されません。これは間接的に文書化されています。シェル操作マニュアルでは:すべてのトークン化と解析は、「the」コマンドが実行される前に発生します。extglob
トークン化中に認識される新しいパターン一致演算子を追加して、言語構文を変更できます。
コマンドが到着したときにまだ実行されていないため、単一項目として処理されずshopt
(履歴拡張がないだけであるなど)、履歴拡張( )や制御演算子を試みたものとして処理されます。!(
!
(
!(
@(
どちらの場合も、解析がこの指示に達すると通常エラーが発生します。行!(...)
の先頭でも負のtime
サブシェルパイプの後ろにあっても同じです。 " unexpected token `('
"は、その場所でサブシェル式を許可できないことを意味します。
サブシェルで一時的にextglobを有効にしたい場合は、少し面倒です。 1つの回避策は必須のglobを使用する関数を定義し、extglobを再び無効にし、それからextglobが有効なサブシェルでこの関数を呼び出します。
shopt -s extglob
f() { ls "a."!(b*) ; }
shopt -u extglob
(
shopt -s extglob
f
)
非常にかさばる。
構文解析前に処理されるため、複合コマンド内でエイリアスを生成しても同じ効果が発生します。
if true
then
alias foo=echo
foo bar
fi
foo xyz
エイリアスのために印刷foo: command not found
してから印刷します。xyz
はいif
作成されましたが完了するまで使用できません。