#!/usr/bin/env bash
# @(#) s1 Demonstrate execution of created shell command.
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }
db() { ( printf " db, ";for _i;do printf "%s" "$_i";done;printf "\n" ) >&2 ; }
db() { : ; }
C=$HOME/bin/context && [ -f $C ] && $C
pl " Create, display, attempt to execute shell command:"
cmd='count=$( wc -l < s1 )'
pe " Command is \"$cmd\""
$cmd
pl " Write command to file, use as input to shell:"
echo "$cmd" > f1
echo "echo \$count" >> f1
cat f1
bash f1
pe " Current value of count is \"$count\""
pl " Write command to file with here document, use as input to shell:"
cat <<EOF > f1
$cmd
echo "count is \$count"
EOF
cat f1
bash f1
pe " Current value of count is \"$count\""
pl " Create, display, attempt to execute shell command, using eval:"
unset count
echo " count before eval is \"$count\""
cmd='count=$( wc -l < s1 )'
pe " Command is \"$cmd\""
pe " Current value of count is \"$count\""
eval $cmd
echo " count after eval is \"$count\""
pl " Create, display, attempt to execute shell command, using source:"
unset count
echo " count before source is \"$count\""
cmd='count=$( wc -l < s1 )'
pe " Command is \"$cmd\""
echo "$cmd" > f1
pe " Current value of count is \"$count\""
source f1
echo " count after source is \"$count\""
exit 0
producing:
% ./s1
Environment: LC_ALL = C, LANG = C
(Versions displayed with local utility "version")
OS, ker|rel, machine: Linux, 2.6.26-2-amd64, x86_64
Distribution : Debian GNU/Linux 5.0.8 (lenny)
bash GNU bash 3.2.39
-----
Create, display, attempt to execute shell command:
Command is "count=$( wc -l < s1 )"
./s1: line 14: count=$(: command not found
-----
Write command to file, use as input to shell:
count=$( wc -l < s1 )
echo $count
51
Current value of count is ""
-----
Write command to file with here document, use as input to shell:
count=$( wc -l < s1 )
echo "count is $count"
count is 51
Current value of count is ""
-----
Create, display, attempt to execute shell command, using eval:
count before eval is ""
Command is "count=$( wc -l < s1 )"
Current value of count is ""
count after eval is "51"
-----
Create, display, attempt to execute shell command, using source:
count before source is ""
Command is "count=$( wc -l < s1 )"
Current value of count is ""
count after source is "51"
The double quotes around "some simple command" are causing the command substitution contained therein to be executed. Use single quotes to get the actual literal command displayed. Then, use eval to force the shell to evaluate the line where you want to run the command twice. The first pass replaces "eval $CMD" with "CNT=$(who|grep -c username)" then it gets executed.
eval can be dangerous if a user can affect what is eval'd, but since you are controlling the command to be eval'd you should be ok here.
It is indeed possible, but you have to be aware about the different number of times the line gets evaluated with and without eval.
If you use eval var='$(...)' to execute it you should probably print it with the same number of evals. But to be honest i have a feeling that your whole script is not planned very well because the structures you use are looking wrong anyway. I may be wrong, but if you post your whole script and tell us what you want to achieve we could find a better way to do it than with such crooked measures.
If you try double quotes instead of single quotes, I think it becomes a bit more straight forward, you should then escape the double quotes with a backslash, plus the $-signs that you wish to protect from evaluation during assignment:
CMD="CNT=\$( grep -c -e \"Non-option program arguments: '$PACKAGE_1'\" -e \"Checking whether to refresh metadata for $REPO_1\" -e \"Selecting '$PACKAGE_1-3.5.0-7.x86_64' from repository '$REPO_1' for installation.\" \"$LOG_FILE_1\" )"
If you use a here-document you do not need the double quotes around the string and therefore you do not need to escape the double quotes inside:
read CMD << EOF
CNT=\$( grep -c -e "Non-option program arguments: '$PACKAGE_1'" -e "Checking whether to refresh metadata for $REPO_1" -e "Selecting '$PACKAGE_1-3.5.0-7.x86_64' from repository '$REPO_1' for installation." "$LOG_FILE_1" )
EOF
And you need to use double quotes around variable references:
printf "%s\n" "$CMD"
eval "$CMD"
A third option, since this is just a deferred command in a variable and there is no reason for evaluating one $sign earlier than the next you could use:
read CMD << "EOF"
CNT=$( grep -c -e "Non-option program arguments: '$PACKAGE_1'" -e "Checking whether to refresh metadata for $REPO_1" -e "Selecting '$PACKAGE_1-3.5.0-7.x86_64' from repository '$REPO_1' for installation." "$LOG_FILE_1" )
EOF
Then you do not need to escape any character, but then the variable names will show up when you print the content of $CMD, which you may or may not prefer...
My script is not doing more than the example I gave.
#!/bin/bash
#
My_CMD1="some texte and parameter $PARAM1 $PARAM2 without quote"
# Want to print to screen
# for debugging
echo "The command is : $MY_CMD1"
# now execute it
$MY_CMD1
# OK no problem with this case
#
#Trying this one
#
PARAM1="No"
PARAM2="Not installed"
PARAM3="FreeNX"
PARAM4="My_freenx_Directory"
PARAM5="/tmp/install_test/freenx.log"
#
zypper info -r $PARAM4 > $PARAM5
#
# We try to verify if the log file contains the information
# that prove that the software is not installed
# 4 parameters are nedeed
#
# For good understanding I replace all quote (simple or double) with this : %
# and each time the single quote ( ' ) is necessary I put it in the right place
# So the next line is not the real one
#
MY_CMD2=%CNT=$( grep -c -e %some_text1 $PARAM1% -e %some_text2 '$PARAM2'% -e %some_text3-1 $PARAM3-1 some_text3-2 '$PARAM4'% -e %some_text4% $PARAM4% $PARAM_5 ) %
#
# If the software is not installed, CNT = 4
#
# now try to print the command to screen ( very important for debugging )
echo "The command is : $MY_CMD2"
# now execute it
$MY_CMD2
# Problem with this case
#
I get this working with 2 conditions :
1�)I must separate the variable content (because of ( " ) and ( ' ) ) for printing or for execute
2�)I use eval for execute --> eval $MY_CMD2
#!/bin/bash
#
My_CMD1="some texte and parameter $PARAM1 $PARAM2 without quote"
# Want to print to screen
# for debugging
echo "The command is : $MY_CMD1"
# now execute it
$MY_CMD1
# OK no problem with this case
#
#Trying this one
#
PARAM1="No"
PARAM2="Not installed"
PARAM3="FreeNX"
PARAM4="My_freenx_Directory"
PARAM5="/tmp/install_test/freenx.log"
#
zypper info -r $PARAM4 > $PARAM5
#
# We try to verify if the log file contains the information
# that prove that the software is not installed
# 4 parameters are nedeed
#
# For good understanding I replace all quote (simple or double) with this : %
# and each time the single quote ( ' ) is necessary I put it in the right place
# So the next line is not the real one
#
# MY_CMD3 is use for echoing to the screen and have to put some more single and double quote.
#
MY_CMD3=%CNT=$( grep -c -e %some_text1 $PARAM1% -e %some_text2 '$PARAM2'% -e %some_text3-1 $PARAM3-1 some_text3-2 '$PARAM4'% -e %some_text4% $PARAM4% $PARAM_5 ) %
#
# MY_CMD4 use some different single and double quote ,where single quote are mandatory.
#
$MY_CMD4=%CNT=$( grep -c -e %some_text1 $PARAM1% -e %some_text2 %%'$PARAM2'%% -e %some_text3-1 $PARAM3-1 some_text3-2 %%'$PARAM4'%% -e %some_text4% $PARAM4% $PARAM_5 ) %
#
# now try to print the command to screen ( very important for debugging )
echo "The command is : $MY_CMD3"
# now execute it
eval $MYCMD4
# No Problem with this case
#
CMD_3 -->
CMD='CNT=$( grep -c -e "Non-option program arguments: '"'$PACKAGE_1'"'" -e "Checking whether to refresh metadata for '$REPO_1'" -e "Selecting '"'FreeNX-0.7.3-22.1.x86_64'"' from repository '"'$REPO_1'"' for installation." '$LOG_FILE_1' ) '
CMD_4 -->
CMD='CNT=$( grep -c -e "Non-option program arguments: '"'"'$PACKAGE_1'"'"'" -e "Checking whether to refresh metadata for $REPO_1" -e "Selecting '"'"'FreeNX-0.7.3-22.1.x86_64'"'"' from repository '"'"'$REPO_1'"'"' for installation." $LOG_FILE_1 ) '