複合コマンド内でのみシェル オプションを設定すると、後続の拡張グロブが失敗することがわかりましたextglob
。複合コマンドの外部でシェル オプションを設定する必要がありますか? 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
。