1

How can I create a variable with a file name format like :

FileName pattern: SnapshotIR__somenumber.csv

I tried something like :

TODAY=$(date +"%m%d%Y")    
SNAPSHOT = $(SnapshotIR$TODAY*.csv)

I get error like :

test.sh: line 2: SnapshotIR02122013_2239.csv: command not found
test.sh: line 2: SNAPSHOT: command not found

so, when I want to use with if

if [ -f SnapshotIR$TODAY*.csv]  -> works 
if [ -f ${SNAPSHOT} ]           -> does not work (I get the above error)
1
  • 1
    To help you with more than how to assign variables you might want to include your whole script.
    – N.N.
    Commented Feb 12, 2013 at 9:48

3 Answers 3

2
SNAPSHOT = $(SnapshotIR$TODAY*.csv)

You can't have a space in assignments. Furthermore, $(…) is a command substitution: this line attempts to execute SnapshotIR02122013_2239.csv as a program.

In bash, ksh or zsh, set SNAPSHOT to be an array containing the list of matching file names.

SNAPSHOT=("SnapshotIR$TODAY"*.csv)

If there is no matching file, the pattern is left unexpanded. In bash or zsh, set the nullglob option to get an empty array instead. In ksh, put ~(N) at the beginning of the pattern (i.e. SNAPSHOT=(~(N)"SnapshotIR$TODAY"*.csv)). You can then test if there were any matching files by testing the length of the array.

shopt -s nullglob
SNAPSHOT=("SnapshotIR$TODAY"*.csv)
if [ ${#SNAPSHOT} -eq 0 ]; then
  echo 1>&2 "No snapshot file for $TODAY"
  exit 2
elif [ ${#SNAPSHOT} -gt 1 ]; then
  echo 1>&2 "Multiple snapshot files for $TODAY, I don't know which one to pick"
  exit 2
fi
echo "The snapshot file is ${SNAPSHOT[0]}"

In shells without arrays, you can use a function that receives the list of matches and counts them. If there is no match, the function receives the pattern unexpanded.

set_snapshot () {
  if [ $# -gt 1 ]; then
    echo 1>&2 "Multiple snapshot files for $TODAY, I don't know which one to pick"
    exit 2
  elif [ -e "$1" ]; then
     SNAPSHOT=$1
  else
    echo 1>&2 "No snapshot file for $TODAY"
    exit 2
  fi
}
set_snapshot "SnapshotIR$TODAY"*.csv
echo "The snapshot file is $SNAPSHOT"

(Note that using [ -e "$1" ] to test whether the pattern was left unexpanded fails in pathological cases such as [0-9] when there is no file whose name is a single digit but there is a file with the 5-character name [0-9]. This can't happen with only * or ? metacharacters since they match themselves.)

The following approach works to some extent:

SNAPSHOT=SnapshotIR$TODAY"*.csv
if [ -e $SNAPSHOT ]; then …

Since the expansion $SNAPSHOT is left unquoted, it is treated as a whitespace-separated list of wildcard patterns, which is ok here. However, if there is more than one matching file, the matches will be seen as separate arguments by the [ command, and that will cause a syntax error. (With specially-crafted file names, it could even cause a wrong result.) So I don't recommend this approach, it's too brittle.

2
  • Thanks for showing the correct methods. First example should use ${#snapshot[@]}, ideally (( ! ${#snapshot[@]} )), though in this specific case testing the 0th element will give the illusion of working anyway.
    – ormaaj
    Commented Feb 23, 2013 at 0:23
  • @ormaaj Right. In ksh and bash, ${#foo} is the length of the first element of the array. When dealing with an array of file names, which can't be empty, ${#foo} is 0 only if the array is empty. Commented Feb 24, 2013 at 0:32
1

When you use $() shell will execute the content inside braces as command.
You're not allowed to use spaces before/after = symbol.

So your command will be as

SNAPSHOT=SnapshotIR$TODAY*.csv

or

SNAPSHOT=SnapshotIR${TODAY}*.csv

ps. If you need to make some operations with this files in next step, it's better to use for cycle like

for file in SnapshotIR${TODAY}*.csv ; do smth ; done

cause in case you have several files matching your pattern, [ -f ${SNAPSHOT} ] contruction will return an error like:

[ -f f* ] && echo ok
-bash: [: filename: binary operator expected
1

Do not use spaces around = when assigning variables.

Also, I do not think you want to enclose what SNAPSHOT is assigned to in $( ) as that tries to execute it as a command.

On a side note, consider to lowercase your variables.

So what you want may be

today=$(date +"%m%d%Y")    
snapshot=SnapshotIR$today

if [ -f ${snapshot}*.csv ]
1
  • 2
    Beware that if more than one file matches ${snapshot}*.csv, all hell will break loose. Commented Feb 13, 2013 at 0:47

You must log in to answer this question.

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