My bash script writes an another bash script using printf.
printf "#!/bin/bash
HOME=${server}
file=gromacs*
file_name=\$(basename "\${file}")
date=\$(date +"\%m_\%d_\%Y")
for sim in \${HOME}/* ; do
if [[ -d \$sim ]]; then
simulation=$(basename "\$sim")
pushd \${sim}
cp \$file \${server}/\${results}/\${file_name}.\${simulation}.\${date}
echo "\${file_name}\ from\ \${simulation}\ has\ been\ collected!"
popd
fi
done" > ${output}/collecter.sh
Here there is a problem in escappiong of the elements within date variable
date=\$(date +"\%m_\%d_\%Y")
where the below part did not work properly
"\%m_\%d_\%Y"
it results in incomplete of a new bash script produced by printf.
How it should be fixed?
Thanks!
You have to escapes in
printf
with esscaps, e. g.:should print
date=\$(date +"%m_%d_%Y")
. But you should avoid usingprintf
, because you don't use it's capabilities. Instead you could cat the string to the file:This would allow you to avoid many escapes, and make the code more readable.
Try this
Use a quoted heredoc.
Note:
cat <<'EOF'
), no substitutions are performed, so no escaping is needed. We're thus able to write our code exactly as we want it to exist in the generated file.printf %q
to escape values in such a way as to evaluate back to their original values. Otherwise, a variable containing$(rm -rf ~)
could cause the given command to be run (if it were substituted inside literal single quotes, making the contents$(rm -rf ~)'$(rm -rf ~)'
would escape them).file=( gromacs* )
makes the storage of the result in an array explicit, and the following code checks for both the case where we have more than one result, and the case where our result is the original glob expression (meaning no matches existed)."$HOME"/*
, not$HOME/*
-- otherwise you'll have problems whenever a user has a home directory containing whitespace (and yes, this does happen -- consider Windows-derived platforms where you have/Users/Firstname Lastname
, or sites where you've mounted a volume for home directories off same).pushd
andpopd
are an interactive extension, as opposed to a tool intended for writing scripts. Since spawning an external program (such ascp
) involves a fork() operation, and any directory change inside a subshell terminates when that subshell does, you can avoid any need for them by spawning a subshell,cd
'ing within that subshell, and then using theexec
builtin to replace the subshell's PID with that ofcp
, thus preventing thefork
that would otherwise have taken place to allowcp
to be started in a separate process from the shell acting as its parent.