MacOSの拡張globパターンの構文エラーのため、bash `if`ブロックの内容を実行できません。

MacOSの拡張globパターンの構文エラーのため、bash `if`ブロックの内容を実行できません。

簡潔なバージョン:

私のMacのbashブロック内で拡張globを開くと、ブロック全体がifアクティブになっても、ブロック内に含まれる拡張globパターンの構文エラーが原因で失敗します。他のコンピュータでは問題はありません。なぜ?

長いバージョン:

ifファイル全体に次の条件を設定しました.bashrc。シェルの初期化中に実行されるif他のファイルにも同様の文があります。.*後で問題が発生した場合にファイルが再帰的に実行されないようにします。

if [ -n "${_BASHRC_INIT}" ] ; then
export _BASHRC_INIT="True"

...
...
...

unset _BASHRC_INIT
fi

laa.bashrc拡張globに依存するこの関数はmyで定義されています。関数を定義する直前に有効にします。この機能は、.*除外および一致するディレクトリ内の.すべてのファイルを表示します..lsエイリアスを指定したため、ls --color=autoファイル形式の色も表示されますgrepifブロック内部ではないときに機能します。

shopt -s extglob
laa() {
  if [[ $# -eq 1 ]]; then
    exec 3>&1                                 # Another file descriptor for this STDOUT
    _items=$(cd "${1}"; ls -d .!(|.)?* 1>&3)  # This requires extended glob
                                              # `shopt -s extglob` to enable
    exec 3>&-                                 # Close file descriptor
  elif [ $# -gt 1 ]; then
    exec 3>&1
    for i in $@; do
      _items=$(cd $i; echo "$i:" 1>&3; ls -d .!(|.)* 1>&3)
    done
    exec 3>&-
  else
    ls -d .!(|.)*
  fi
}

ブロックにこの抜粋も含まれている場合、ブロックに含まれているコマンドのどれもif私のM1 Macで実行できません。 Windows PCのWSL2(Debian)ではこの問題は発生しません。 Mac はbash 5.2.15Homebrew と WSL の実行がインストールされた状態で動作しますbash 5.1.4

ls特に、次のエラーが原因でコマンドが失敗します。

bash: syntax error near unexpected token `('
bash: `    _items=$( cd "${1}"; ls -d .!(|.)?* 1>&3 )  # This requires extended glob'

入力前に実行すると、ifブロック全体が期待どおりに実行されます。shopt -t extglobこれが私の現在のソリューションです。しかし、これは私の環境で設定したいルールを破ります。私は.*自分のコンピュータで同じファイルを使用しようとします。これは、新しいコンピュータで一貫した環境をすばやく作成するのにも役立ちます。

ブロック内容の追加構文チェックの原因は何ですかif

答え1

ここでは、KSHスタイルの拡張グローブを完全に避けることができます。- 例をご覧ください。現在のディレクトリと親ディレクトリを除くすべての隠しファイルをグローバルに表示する方法


compat516.12 シェル互換モード

コマンド置換解析は拡張globが有効になっているように動作するため(Shoptの組み込みを参照)、extglobパターン(シェル関数の一部など)を含むコマンド置換解析は失敗しません。これは、コマンドを実行してワード拡張を実行する前にextglobを有効にする意図があると仮定します。コマンドが実行されたときにextglobが有効になっていないと、単語の拡張に失敗します。

たとえば、考えてみましょう。

#!/bin/bash

echo "$BASH_VERSION"

laa() {
  if [[ $# -eq 1 ]]; then
    exec 3>&1                                 # Another file descriptor for this STDOUT
    _items=$(cd "${1}"; ls -d .!(|.)?* 1>&3)  # This requires extended glob
                                              # `shopt -s extglob` to enable
    exec 3>&-                                 # Close file descriptor
  elif [ $# -gt 1 ]; then
    exec 3>&1
    for i in $@; do
      _items=$(cd $i; echo "$i:" 1>&3; ls -d .!(|.)* 1>&3)
    done
    exec 3>&-
  fi
}

shopt -s extglob
laa .

ここではextglob、関数定義後に実行する前に設定されます(関数が.bashrcファイルから開始された場合)。 bash 5.1では動作します。

$ /bin/bash ./myscript
5.1.16(1)-release
.admins        .cache     .hardinfo  .parallel        .RData            .ssh                       .vboxclient-display-svga-x11.pid  .Xauthority       .zcompdump
.bash_history  .config    .lesshst   .password-store  .Rhistory         .sudo_as_admin_successful  .vboxclient-draganddrop.pid       .xinitrc          .zsh_history
.bash_logout   .dialogrc  .local     .profile         .selected_editor  .test_dot_folder           .vboxclient-seamless.pid          .xscreensaver     .zshrc
.bashrc        .gnupg     .mozilla   .python_history  .spectrum3d       .vboxclient-clipboard.pid  .wget-hsts                        .xsession-errors

5.2では、次のことは行いません。

$ ./src/bash-5.2.15/bash ./myscript
5.2.15(1)-release
./myscript: line 8: syntax error near unexpected token `('
./myscript: line 8: `    _items=$(cd "${1}"; ls -d .!(|.)?* 1>&3)  # This requires extended glob'

しかし、、行動外部コマンド置換の状況は同じであるため、elseブロックを追加した後は次のようになります。

#!/bin/bash

echo "$BASH_VERSION"

laa() {
  if [[ $# -eq 1 ]]; then
    exec 3>&1                                 # Another file descriptor for this STDOUT
    _items=$(cd "${1}"; ls -d .!(|.)?* 1>&3)  # This requires extended glob
                                              # `shopt -s extglob` to enable
    exec 3>&-                                 # Close file descriptor
  elif [ $# -gt 1 ]; then
    exec 3>&1
    for i in $@; do
      _items=$(cd $i; echo "$i:" 1>&3; ls -d .!(|.)* 1>&3)
    done
    exec 3>&-
  else
    ls -d .!(|.)*
  fi
}


shopt -s extglob
laa .

どちらの場合も、コードは失敗します。 5.2では、より高速です。

$ ./src/bash-5.2.15/bash ./myscript
5.2.15(1)-release
./myscript: line 8: syntax error near unexpected token `('
./myscript: line 8: `    _items=$(cd "${1}"; ls -d .!(|.)?* 1>&3)  # This requires extended glob'
$ 
$ /bin/bash ./myscript
5.1.16(1)-release
./myscript: line 18: syntax error near unexpected token `('
./myscript: line 18: `    ls -d .!(|.)*'

bash 5.1の動作を使用する必要がある場合は、BASH_COMPAT=51.bashrcファイルの関数定義の前にこれを設定できます。

関連情報