bashfunctionshoptextglob

bash extglob pattern matching breaks when enclosed in a function


This works

shopt -s extglob
find /usr/!(^*|@*) -maxdepth 0 -cmin +1 -exec echo {} \;
shopt -u extglob

This returns an error

syntax error near unexpected token `('

function test {
  shopt -s extglob
  find /usr/!(^*|@*) -maxdepth 0 -cmin +1 -exec echo {} \;
  shopt -u extglob
}

test

What am I missing, that would permit me to use this in a function?


Solution

  • The problem is bash needs extglob to be turned on at two times:

    1. when parsing the script

    2. when executing the actual command

    By including the shopt into the function body, 1. is not satisified. If you broaden the scope of the shopt to include the function declaration, too, bash will parse the function correctly, but it will fail when running it (i.e. 2. is not satisfied):

    shopt -s extglob
    function test {
        find /usr/!(^*|@*) -maxdepth 0 -cmin +1 -exec echo {} \;
    }
    shopt -u extglob
    

    The error:

    find: ‘/usr/!(^*|@*)’: No such file or directory
    

    So, just turn shopt extglob on at the beginning of the script and that's it. Or, if you really need it to be off elsewhere, turn it on and off both inside and outside the function:

    #! /bin/bash
    shopt -s extglob
    function test {
        shopt -s extglob
        find /usr/!(^*|@*) -maxdepth 0 -cmin +1 -exec echo {} \;
        shopt -u extglob
    }
    shopt -u extglob
    
    test