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

On the console I might execute something like this:

1
2
  touch /tmp/file-$(date --iso-8601) 
  ls /tmp/file-*
/tmp/file-2019-03-08
Example command substitution

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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  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
Example avoiding command substitution

But, if you really want to use command substitution you can use backticks directly.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  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
Example using backticks for command substitution

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.