複合コマンドでbashオプションを設定する

複合コマンドでbashオプションを設定する

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作成されましたが完了するまで使用できません。

関連情報