Syntax error near unexpected token `('

50,064

Solution 1

rm !(*.sh) is a extglob syntax which means remove all files except the ones that have the .sh extension.

In your interactive bash instance, the shell option extglob is on :

$ shopt extglob 
extglob         on

Now as your script is running in a subshell, you need to enable extglob by adding this at the start of the script :

shopt -s extglob

So your script looks like :

#!/bin/bash
shopt -s extglob
rm -rf -- !(*.sh)

EDIT :

To remove all files except .sh extension ones use GLOBIGNORE (as you don't want to enable extglob) :

#!/bin/bash
GLOBIGNORE='*.sh'
rm -rf *

Example :

$ ls -1
barbar
bar.sh
egg
foo.sh
spam

$ GLOBIGNORE='*.sh'

$ rm *

$ ls -1
bar.sh
foo.sh

Solution 2

Ok, it's a cross-post, but I have to write an answer. ;)

You could use find instead

find . -maxdepth 1 ! -name '*.sh' -exec rm -rf {} \;

Solution 3

You need to turn extglob on:

shopt -s extglob
Share:
50,064

Related videos on Youtube

Tal
Author by

Tal

Updated on September 18, 2022

Comments

  • Tal
    Tal over 1 year

    When I use below code in Ubuntu terminal, it works fine:

    rm !(*.sh) -rf
    

    But if I place the same line code in a shell script (clean.sh) and run the shell script from terminal, it throws an error:

    clean.sh script:

    #!/bin/bash
    rm !(*.sh) -rf
    

    The error I get:

    ./clean.sh: line 2: syntax error near unexpected token `('
    ./clean.sh: line 2: `rm !(*.sh) -rf'
    

    can you help?

  • choroba
    choroba almost 9 years
    @Pilot6: See man bash. It enables extended globbing like !(...).
  • Tal
    Tal almost 9 years
    can i change my command that do the same without run this? shopt -s extglob
  • Tal
    Tal almost 9 years
    can i change my command that do the same without run this? shopt -s extglob?
  • heemayl
    heemayl almost 9 years
    @Tal check my edits..
  • Tal
    Tal almost 9 years
    thanks :) (stack overflaw make me write 15 character in comment :( :( :( )
  • Tal
    Tal almost 9 years
    but here there a two good answers!
  • heemayl
    heemayl almost 9 years
    @Tal No problem..you can select any one.. Me or A.B. won't mind at all..
  • Guntram Blohm
    Guntram Blohm almost 9 years
    This should be the accepted answer, since it actually answers the question, while the other one just describes a workaround.
  • Paddy Landau
    Paddy Landau over 8 years
    If you want GLOBIGNORE for only the rm command and nothing else, enclose in parentheses and use a semicolon thus: ( GLOBIGNORE='*.sh'; rm * )
  • Gaël J
    Gaël J over 2 years
    Highlighting the fact at it has to be at the start of the script, I had it in the middle and it was not working