This was originally published here, it has been re-published with permission.
How can I execute a command that uses command substitution in CFEngine?
On the console I might execute something like this:
Listing 1: Example command substitution
touch /tmp/file-$(date --iso-8601)
ls /tmp/file-*
/tmp/file-2019-03-08
I recommend not executing commands using substitution. Instead, prepare all that you need up front. Get the result of the data command and put it into a CFEngine variable, then use the CFEngine variable directly.
bundle agent main
{
vars:
"date" string => execresult( "date --iso-8601=second", useshell );
"command" string => "/usr/bin/touch /tmp/file-$(date)";
"result" string => execresult( $(command), useshell );
reports:
"CFEngine $(sys.cf_version)";
"Executed $(command)" if => isvariable( result );
"Files:$(const.n)$(with)" with => join( "$(const.n)", lsdir( "/tmp/", "file-.*", false ));
}
R: CFEngine 3.13.0
R: Executed /usr/bin/touch /tmp/file-2019-03-08T11:34:37-06:00
R: Files:
file-2019-03-08T11:34:21-06:00
file-2019-03-08T11:34:34-06:00
file-2019-03-08T11:34:37-06:00
file-2019-03-08T11:34:24-06:00
But, if you really want to use command substitution you can use backticks directly.
bundle agent main
{
vars:
"command" string => "/usr/bin/touch /tmp/file2-`date --iso-8601=second`";
"result" string => execresult( $(command), useshell );
reports:
"CFEngine $(sys.cf_version)";
"Executed $(command)" if => isvariable( result );
"Files:$(const.n)$(with)" with => join( "$(const.n)", lsdir( "/tmp/", "file2-.*", false ));
}
R: CFEngine 3.13.0
R: Executed /usr/bin/touch /tmp/file2-`date --iso-8601=second`
R: Files:
file2-2019-03-08T11:36:30-06:00
file2-2019-03-08T11:36:35-06:00
Why is it so?
CFEngine expands variables wrapped in $()
and ${}
and functions are skipped
(e.g. execresult()) if they have parameters that are variables that do not dereference.