簡潔なバージョン:
私の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
ファイル形式の色も表示されますgrep
。if
ブロック内部ではないときに機能します。
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.15
Homebrew と 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スタイルの拡張グローブを完全に避けることができます。- 例をご覧ください。現在のディレクトリと親ディレクトリを除くすべての隠しファイルをグローバルに表示する方法。
compat51
下6.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ファイルの関数定義の前にこれを設定できます。