The following works when pasted directly into my bash terminal (I call bash explicitly, bash version: 4.4.19(1)-release (x86_64-pc-linux-gnu)
)
for filename in /home/dean/Downloads/!(*example).txt; do
echo "${filename}"
done
This command echoes back all of the txt files that do not have 'example' in the filename.
But when I convert this into a script called temp.sh
, chmod +x temp.sh
and call it by ./temp.sh
:
#!/usr/bin/env bash
for filename in /home/dean/Downloads/!(*example).txt; do
echo "${filename}"
done
I get the following error:
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'
I fail to understand the problem here. Why is it doing exactly what I want in the shell but not in the script.
Edit (to answer panki's question):
The difference between when env
is called in shell/terminal and when env
is called in shell/script:
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
Best Answer
The
!(...)
Korn shell extended operator is only available inbash
when you turn theextglob
option on (it is off by default).You may have
extglob
turned on in your interactive shell via~/.bashrc
or other initialization file, but notice that those files are not sourced when running scripts, and that option is not inherited from the calling shell (unless theBASHOPTS
variable in the environment, but it would be a bad idea to have it there).Explicitly turning it on with
at the beginning of your script should work.
Notice that the
shopt -s extglob
only has effect beginning with the next line which wasn't already parsed. This means that you cannot useshopt -s extglob
likeset -f
, to only turn the extended patterns on in a subshell:You'd have to do something like: