I am having trouble getting the basics of Bash scripting down. Here's what I have so far:

FILES="/home/john/my directory/*.txt"

for f in "${FILES}"
  echo "${f}"

All I want to do is list all the .txt files in a for loop so I can do stuff with them. But the space in the my directory and the asterisk in *.txt just aren't playing nicely. I tried using it with and without double quotes, with and without curly braces on variable names and still can't print all the .txt files.

This is a very basic thing, but I'm still struggling because I'm tired and can't think straight.

What am I doing wrong?

I've been able to successfully apply the script above if my FILES don't have a space or an asterisk... I had to experiment with or without the use of double quotes and braces to get it to work. But the moment I have both spaces and an asterisk, it messes everything up.


Inside quotes, the * will not expand to a list of files. To use such a wildcard successfully, it must be outside of quotes.

Even if the wildcard did expand, the expression "${FILES}" would result in a single string, not a list of files.

One approach that would work would be:

DIR="/home/john/my directory/"
for f in "$DIR"/*.txt
  echo "${f}"

In the above, file names with spaces or other difficult characters will be handled correctly.

A more advanced approach could use bash arrays:

FILES=("/home/john/my directory/"*.txt)
for f in "${FILES[@]}"
  echo "${f}"

In this case, FILES is an array of file names. The parens surrounding the definition make it an array. Note that the * is outside of quotes. The construct "${FILES[@]}" is a special case: it will expand to a list of strings where each string is one of the file names. File names with spaces or other difficult characters will be handled correctly.

  • 1
    great that worked – John Sep 20 '14 at 5:18
  • It's worth noting that if you're passing paths like this around through functions, you need to ensure you quote the variable on its own rather than concatenating it as part of a larger string: for f in "$DIR"/*.txt = fine for f in "$DIR/*.txt" = breaks – pospi Aug 6 '16 at 7:28

While using arrays as shown by John1024 makes a lot more sense, here, you can also use the split+glob operator (leaving a scalar variable unquoted).

Since you only want the glob part of that operator, you need to disable the split part:

#! /bin/sh -
# that also works in any sh, so you don't even need to have or use bash

file_pattern="/home/john/my directory/*.txt"
# all uppercase variables should be reserved for environment variables

IFS='' # disable splitting

for f in $file_pattern # here we're not quoting the variable so
                       # we're invoking the split+glob operator.
  printf '%s\n' "$f" # avoid the non-reliable, non-portable "echo"

What you can do is to leave only the wildcard characters outside of quotes.
Something like:
for a in "files with spaces"*".txt"
If the wildcards themselves expand to spaces, then you'll need t use a file per line approach, like use ls -l to generate the list of files and use bash read to get each file.


When you want to process on set of files, you consider , at their name may be space or other scape code will be there, So before start your process such as for loop or find command set the IFS bash env variable to :

IFS=$(echo -en "\n\b")

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.