Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filenames with wildcards in variables

Tags:

bash

#!/bin/bash
outbound=/home/user/outbound/
putfile=DATA_FILE_PUT_*.CSV
cd $outbound
filecnt=0
for file in $putfile; do let filecnt=filecnt+1; done
echo "Filecount: " $filecnt

So this code works well when there are files located in the outbound directory. I can place files into the outbound path and as long as they match the putfile mask then the files are incremented as expected.

Where the problem comes in is if I run this while there are no files located in $outbound. If there are zero files there $filecnt still returns a 1 but I'm looking to have it return a 0 if there are no files there.

Am I missing something simple?

like image 587
Matthew Burdine Avatar asked Oct 07 '13 19:10

Matthew Burdine


People also ask

How do you use wildcards in file names?

When used in a filename given as an argument to a command: * An asterisk is replaced by any number of characters in a filename. For example, ae* would match aegis, aerie, aeon, etc.

Do commands interpret wildcards?

Commands can use wildcards to perform actions on more than one file at a time, or to find part of a phrase in a text file. There are many uses for wildcards, there are two different major ways that wildcards are used, they are globbing patterns/standard wildcards that are often used by the shell.


2 Answers

Put set -x just below the #! line to watch what your script is doing.

If there is no matching file, then the wildcard is left unexpanded, and the loop runs once, with file having the value DATA_FILE_PUT_*.CSV.

To change that, set the nullglob option. Note that this only works in bash, not in sh.

shopt -s nullglob
putfile=DATA_FILE_PUT_*.CSV
for file in $putfile; do let filecnt=filecnt+1; done

Note that the putfile variable contains the wildcard pattern, not the list of file names. It might make more sense to put the list of matches in a variable instead. This needs to be an array variable, and you need to change the current directory first. The number of matching files is then the length of the array.

#!/bin/bash
shopt -s nullglob
outbound=/home/user/outbound/
cd "$outbound"
putfiles=(DATA_FILE_PUT_*.CSV)
echo "Filecount: " ${#putfiles}

If you need to iterate over the files, take care to protect the expansion of the array with double quotes, otherwise if a file name contains whitespace then it will be split over several words (and if a filename contains wildcard characters, they will be expanded).

#!/bin/bash
shopt -s nullglob
outbound=/home/user/outbound/
cd "$outbound"
putfiles=(DATA_FILE_PUT_*.CSV)
for file in "${putfiles[@]}"; do
  echo "Processing $file"
done
like image 84
Gilles 'SO- stop being evil' Avatar answered Nov 14 '22 21:11

Gilles 'SO- stop being evil'


You could test if file exists first

for file in $putfile; do
  if [ -f "$file" ] ; then
    let filecnt=filecnt+1
  fi
done

Or look for your files with find

for file in $(find . -type f -name="$putfile"); do
  let filecnt=filecnt+1
done

or simply (fixed)

filecnt=$(find . -type f -name "$putfile" | wc -l); echo $filecnt
like image 23
LMC Avatar answered Nov 14 '22 21:11

LMC