Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

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

#!/bin/bash
FILES="/home/john/my directory/*.txt"

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

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.

share|improve this question

3 Answers 3

up vote 11 down vote accepted

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:

#!/bin/bash
DIR="/home/john/my directory/"
for f in "$DIR"/*.txt
do
  echo "${f}"
done

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

A more advanced approach could use bash arrays:

#!/bin/bash
FILES=("/home/john/my directory/"*.txt)
for f in "${FILES[@]}"
do
  echo "${f}"
done

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.

share|improve this answer
    
great that worked –  John Sep 20 '14 at 5:18

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")
share|improve this answer

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.
do
  printf '%s\n' "$f" # avoid the non-reliable, non-portable "echo"
done
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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