I'm trying to set up an sh script that will run every 30 minutes. During each run, I want to check a directory for the presence of at least one .RAW file. Upon finding that file extension, I will have other code to execute, but right now I'm having trouble figuring out the correct if statement to use.

I know this code example isn't the most ideal way to do it, but here's the code I tried which is obviously wrong:

cd ./dir/
if [ ! -f "*.RAW"]; then
  echo "No files!"
  echo "Yes files!"

How can I correctly test for the presence of the .RAW extension?


4 Answers 4


With zsh:

if (($#files)); then
  echo Yes
  echo No

If you're only interested in regular files (or symlinks to regular files) as your -f implies, that would be:




has_regfiles_by_extension() {
  for ext do
    for file in .*."$ext" ."$ext" *."$ext"; do
      [ -f "$file" ] && return
    return 1

if has_regfiles_by_extension RAW raw; then
  echo YES
  echo NO

If you wanted to use ls instead, you could do:

if ls -Aq | grep -q '\.RAW$'; then
  echo yes
  echo no

One of the benefits is that if the directory is not readable, you'll get an error message (instead of being silently ignored in the case of shell globs).

  • What is zsh? I apologize, I'm not very knowledgeable with shell scripting yet. I'm just using sh, and I'm getting syntax errors for unexpected '(' in the "files=(*.RAW(ND-.))" line.
    – Alex26
    Commented Aug 22, 2015 at 17:35
  • @Alex26, zsh is one of the most advanced Unix shells. By POSIXly, I mean compatible with the standard sh syntax as specified by POSIX. Many shell implementations understand that syntax (dash, bash, ksh, yash, zsh in sh emulation...) and all modern Unix-like operating sytems have a command called sh (typically, one of the above) that can interpret it which makes it for the most portable alternative. Commented Aug 22, 2015 at 17:59

Your example answer is almost correct. First, you need to separate the testing string ".RAW" from the closing ]:

if [ ! -f "*.RAW" ];

You can do shell globbing in this context by taking the asterisk outside of the quotes. So the finished command would be:

if [ ! -f *".RAW" ];

However, this approach isn't so useful if you want to use the .RAW files. If that's the case, I'd compare the extension of each file in the directory like so:

for file in "test/"*; do
    if [ "${file##*.}" = "RAW" ]; then
        echo "Found raw file"

The Bash syntax ${var##*.} is a part of the clever shell parameter expansion you can do. You can find more information on the GNU website.

  • 1
    [ ! -f *".RAW" ] only ever makes for a valid test/[ expression in the case there is 0 or 1 RAW file in the current directory. Commented Aug 23, 2015 at 10:45
  • 1
    Note that ${var##*.} is not bash specific. It's standard sh syntax (actually introduced by ksh). Commented Aug 23, 2015 at 10:45
  • My bad. I remember reading the *"ext" syntax on a different SE question, but I might've used it in the wrong way.
    – raehik
    Commented Aug 23, 2015 at 15:58

Thanks for all the help, although I haven't been able to get some of these to work.

I did, however, successfully implement code I found in an answer to another question! (https://unix.stackexchange.com/a/87476)

export DIR=./folder
if ls ${DIR}/*.RAW &>/dev/null
  echo "Yes!"
  echo "No!"
  • Note that export is to export a shell variable to the environment of all the commands it runs. It makes little sense here as none of the commands you run make use of that environment variable. Commented Aug 23, 2015 at 10:30
  • Note that &> is not standard sh syntax. It's only recognised by bash (the shell where it originated where other shells like csh, tcsh or zsh have >& instead) and recent versions of zsh. Commented Aug 23, 2015 at 10:32
  • Leaving a variable unquoted like that has a very special meaning. It's like invoking a split+glob operator. It doesn't make sense here. Commented Aug 23, 2015 at 10:33
  • ls will return false if it fails to list any of the file or directories it is passed as argument. For instance, it will return false if ${DIR}/*.RAW has no match (because in that case ${DIR}/*.RAW expands to ./folder/*.RAW and there won't be any file by that name. Or it could return false, because for instance one of the .RAW files passed to ls from the expansion (by the shell) of ${DIR}/*.RAW is a directory which you don't have read access to. Commented Aug 23, 2015 at 10:36
  • Note that by default, shells exclude files whose name starts with . from the expansion of globs like *.RAW, so this approach may fail to detect RAW files. Hence the (D) zsh glob qualifier in my answer (there's no equivalent in standard sh syntax unfortunately). Commented Aug 23, 2015 at 10:38

Two Bourne Shell Solutions

With the Bourne shell (which doesn't support arrays, or shell options like nullglob or failglob) you have to work around the fact that a non-zero exit status or the glob itself will be returned if a glob isn't found. For example:

if [ -n "`ls *.RAW 2> /dev/null`" ]; then
    echo "At least one RAW file found!"
    echo "No RAW files found."

In general, one shouldn't rely on the output of the ls command, but this is sufficient for your use case and works around the limitations of the Bourne shell. If you really want to use only shell built-ins, you have to use assignment and explicitly test for the glob itself as an error condition. For example:

if [ "$files" = "*.RAW" ]; then
    echo "No RAW files found."
    echo "At least one RAW file found!"
  • No. [[ *.RAW =~ RAW ]] is a test for wether the *.RAW string is matched by the RAW regular expression (which obviously it is) Commented Aug 23, 2015 at 9:06
  • [ -n "$(ls *.RAW 2> /dev/null)" ] is wrong. First, there's the problem of file names starting with -. Then, if ommits hidden files. Also, it will fail if the only non-hidden RAW file in the current directory is of type directory (or symlink to directory) and is empty (but for hidden files) or not readable. Commented Aug 23, 2015 at 9:12
  • Also note that the Bourne shell never supported the $(...) syntax. More than likely, the OP is not using the Bourne shell as that shell is no longer in use nowadays (except maybe on Solaris 10 and before if you're using /bin/sh instead of the standard sh in /usr/xpg4/bin). Commented Aug 23, 2015 at 9:14
  • The files=*.RAW; [ "$files" = "*.RAW" ] solution is also plain wrong. It just tests wether *.RAW is the same string as *.RAW. Commented Aug 23, 2015 at 9:19
  • @StéphaneChazelas You are incorrect. files=*.RAW; [ "$files" = "*.RAW" ] works because of the way globbing works when no matches are found. In the absence of nullglob or failglob, when a glob can't be expanded, the shell returns the original glob pattern (in this case, the string *.RAW), which is indeed what the match is looking for.
    – CodeGnome
    Commented Aug 23, 2015 at 19:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .