Search code examples
bashshellglob

When a bash script lists correspond file in directory, but not working properly?


When I try to get file list with some rule.

[[email protected]:~]
$ for x in ./*;do echo $x; done;
/home/mariolu/out_protocol
/home/mariolu/proto
/home/mariolu/proto2
/home/mariolu/protocol_build.3.6.1.sh
/home/mariolu/protocol_build.3.6.sh
/home/mariolu/replace_pb_lite_runtime.sh

It works.

When I list only .sh files. It also works.

[[email protected]:~]

$ for x in ./*.sh;do echo $x; done;
/home/mariolu/protocol_build.3.6.1.sh
/home/mariolu/protocol_build.3.6.sh
/home/mariolu/replace_pb_lite_runtime.sh

But I try to list only .proto files. It does not work properly.

[[email protected]:~]
$ for x in ./*.proto;do echo $x; done;
*.proto

Bash treats $x like string *.proto. But here intention is that $x is a empty list and code breaks from "for loop".


Solution

  • I frequently use shopt in scripts, but when you don't want to, you should explicitly test the result.

    You can test for the glob string itself -

    for x in *.proto;
    do [[ "$x" == '*.proto' ]] && continue
       echo $x
    done
    

    but '*.proto' is actually a valid filename, so it's possible it could get created and this would skip it. That might be a bug or a feature, depending on your needs.

    Another approach is to test if the filename actually exists.

    for x in ./*.proto;
    do [[ -e "$x" ]] && echo $x
    done
    

    This will include any file literally named *.proto if it exists...