How can I execute a command that uses command substitution in CFEngine?

Posted by Nick Anderson
May 13, 2019

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.