218
218

Reputation: 1824

Setting shell variables to contain file lists

I am using the following code to set up a variable containing a series of different file names, which I will then subsequently carry out some functions upon. The files involved are in a different directory (DIRECTORY) to the directory where the code is being executed (CURRENT_DIRECTORY). I thought the following code could be used to change into the directory containing the files cd $DIRECTORY, store the list of files in the variable $FILES and then change back to the original directory (cd $CURRENT_DIRECTORY) where the rest of the code can be executed. However, if I do two echo commands, the first contains the file list when I am in the directory where the files are stored, but the second echo command just prints 'vclist_2d_*.txt', i.e. it interprets this as a string and not a list of files (presumably because I have changed back to the original directory and so it can't find any files that match vclist_2d_*.txt). Why does this happen, and how can I get around this problem (without running everything in the same directory)?

#!/bin/bash
CURRENT_DIRECTORY=`pwd`
DIRECTORY=/home/Documents/NewDirectory/

cd $DIRECTORY
pwd
FILES=vclist_2d_*.txt
echo $FILES
cd $CURRENT_DIRECTORY
echo $FILES

Upvotes: 1

Views: 183

Answers (2)

DevSolar
DevSolar

Reputation: 70223

FILES=vclist_2d_*.txt does not get expanded by the shell. FILES now contains the string vclist_2d_*.txt.

echo $FILES sends echo vclist_2d_*.txt to the shell. The shell then expands the pattern, resulting in either A) the string vclist_2d_*.txt if the pattern does not match anything, or B) a list of the matching file names.

You then change the directory, and repeat the process. At no point is the list of files assigned to any variable.

Now, you could assign the output of echo vclist_2d_*.txt to a variable (SOMEVAR=$(echo vclist_2d_*.txt), but that would solve your problem only halfway. How do you intend to "act on each file in the list"? If you are thinking about a for file in $SOMEVAR, consider what would happen if a filename contains a space...

The easiest, most robust solution to this is to use find instead:

find $DIRECTORY -name "vclist_2d_*.txt" -exec do_something {} +

This results in do_something passed a list of matching files. If the list is very long, it may be split into multiple calls of do_something.

find $DIRECTORY -name "vclist_2d_*.txt" -exec do_something {} \;

This results in do_something being called for each matching file.

If there is a chance that your current directory might contain files matching the pattern passed to find above, you need to escape the asterisk (by adding quotes like I did, or escaping it via \*) to avoid the shell expansion turning your find command into something else.

Upvotes: 1

Etan Reisner
Etan Reisner

Reputation: 80921

You need to save the result of the glob expansion.

Globs are not expanded in simple variable assignments so your current code is expanding the glob when you echo it (which is why you get the behavior you are seeing). Try echo "$FILES" and it won't expand at all for example.

Assignment to arrays, however, do expand so FILES=(vclist_2d_*.txt) will expand the glob immediately and then using echo "${FILES[@]}" later will work correctly.

Upvotes: 4

Related Questions