次のコードは、bashターミナルに直接貼り付けると機能します(bashバージョンを明示的にbashと呼びます:4.4.19(1)-release (x86_64-pc-linux-gnu)
)
for filename in /home/dean/Downloads/!(*example).txt; do
echo "${filename}"
done
このコマンドは、ファイル名に「example」が含まれていないすべてのtxtファイルをエコーバックします。
しかし、これをtemp.sh
、chmod +x temp.sh
というスクリプトに変換し、./temp.sh
で呼び出すと、次のようになります。
#!/usr/bin/env bash
for filename in /home/dean/Downloads/!(*example).txt; do
echo "${filename}"
done
次のエラーが発生します。
dean@dean-thinkpad-p52s:~/Downloads$ ./temp.sh
./temp.sh: line 3: syntax error near unexpected token `('
./temp.sh: line 3: `for filename in /home/dean/Downloads/!(*example).txt; do'
ここでは問題が理解できません。シェルでは必要な機能をスクリプトではなく正確に実行しているのはなぜですか。
編集( panki の質問に答えるため):
シェル/ターミナルでenv
が呼び出されたときとシェル/スクリプトでenv
が呼び出されたときの違い:
dean@dean-thinkpad-p52s:~/Downloads$ diff example_myshell.txt example_called_script.txt
5a6
> _=/usr/bin/env
36,37d36
< TERM=xterm-256color
< Shell=/bin/bash
38a38,39
> Shell=/bin/bash
> TERM=xterm-256color
45c46
< PYENV_Shell=bash
---
> SHLVL=4
47c48
< SHLVL=3
---
> PYENV_Shell=bash
61d61
< _=/usr/bin/env
!(...)
Kornシェル拡張演算子は、bash
オプションをオンにすると(デフォルトではオフになっています)、extglob
でのみ使用できます。
インタラクティブシェルでextglob
を~/.bashrc
またはその他の初期化ファイル。ただし、スクリプトの実行時にこれらのファイルは読み込まれず、そのオプションは呼び出し元のシェルから継承されないことに注意してください(環境内のBASHOPTS
変数を除きますが、これは悪い考えです)そこにそれを持っている)。
明示的にオンにする
shopt -s extglob
スクリプトの冒頭で動作するはずです。
shopt -s extglob
は、まだ解析されていない次の行からのみ効果があります。つまり、shopt -s extglob
お気に入り set -f
、サブシェルで拡張パターンのみをオンにするには:
# this won't work
(
shopt -s extglob
echo !(no such file)
)
あなたは次のようなことをしなければなりません:
(
shopt -s extglob
eval 'echo !(no such file)'
)