web-dev-qa-db-ja.com

ファイルグロビングパターン!(* example)は、bashスクリプトとbashシェルで異なる動作をします

次のコードは、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.shchmod +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

5
Dean Kayton

!(...) 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)'
)
13
mosvy