0

title: bash parameter expansion within a scalar variable

I have a bash script which runs a diff between two files. If there is a diff, I want it to print statement1 and statement2 They are long so i put them into variables, but the echo statement will not expand the parameter. Can this be done in bash?

#!/bin/bash
set -x

source="/home/casper"
target="data/scripts"
statement1="There is a change in ${i}, please check the file"
statement2="or cp /home/casper/${i} /data/scripts/$i"

for i in file1 file2l file3 file4 file5  ; do
    sleep 1 ;
    if diff $source/$i $target/$i 2>&1 > /dev/null ; then
        echo " "
    else
        echo "$statement1 "
        echo "$statement2 "
    fi
done
exit 0

The script seems to work - it finds a diff when it needs to find one. However this is what it prints out.

There is a change in , please check the file
or cp /home/casper/ data/scripts/

I want it to say

There is a change in file2, please check the file
or cp /home/casper/file2 /data/scripts/file2
capser
  • 2,442
  • 5
  • 42
  • 74
  • Replace `2>&1 > /dev/null` by `> /dev/null 2>&1`. – Cyrus Oct 14 '14 at 22:57
  • Replace your first and second `${i}` by `\${i}`. – Cyrus Oct 14 '14 at 22:58
  • Note that `source` is also the name of a command. I would recommend using `src` for your variable name instead. Also, if you are not accessing each `statement` variable more than once, why not just avoid the use of the variables altogether? e.g. `echo "There is a change in ${i}, please check the file"` which would work. – vastlysuperiorman Oct 14 '14 at 23:38
  • `bash` variables and command names exist in different namespaces. Something like `source=foo.sh; source "$source"`, while potentially confusing, works just fine. – chepner Oct 15 '14 at 02:37
  • As an aside, you want `diff -q` and take out the redirections. Redirecting error output is often a very bad idea -- there is a reason error messages are being printed to a different file descriptor in the first place. – tripleee Oct 15 '14 at 04:56
  • Triplee - that is a very good aside. – capser Oct 15 '14 at 13:15

2 Answers2

1

The problem is that $i is expanded when you define statement1 and statement2, not when you expand them. Use a shell function to output the text.

notification () {
    echo "There is a change in $1, please check the file"
    echo "or cp /home/casper/$1 /data/scripts/$1"
}

source="/home/casper"
target="data/scripts"
for i in file1 file2l file3 file4 file5  ; do
    sleep 1 ;
    if diff "$source/$i" "$target/$i" 2>&1 > /dev/null ; then
        echo " "
    else
        notification "$i"
    fi
done
exit 0
tripleee
  • 175,061
  • 34
  • 275
  • 318
chepner
  • 497,756
  • 71
  • 530
  • 681
0

This can be done using eval:

TEMPLATE_MSG="aaa \${VALUE} ccc"
...
VALUE="bbb"
eval echo "${TEMPLATE_MSG}"

But I don't recommend it, because eval is evil :-) Other option is using pattern substitution:

TEMPLATE_MSG="aaa @1@ ccc"
...
VALUE="bbb"
echo "${TEMPLATE_MSG/@1@/${VALUE}}"

So you put some unique pattern in your message (e.g. @1@) and then, when you print the message, you replace it with the content of variable.

danadam
  • 3,350
  • 20
  • 18