Is there any way to do a multiline regex check for a file in CFEngine?

There is no function for searching a file for content. The grep() function operates on lists, not files. However using readfile() and regcmp() I was sill able to search for a multi-line string using only native functionaity

In the example below we first create a file with content that spans multiple lines. Then we read that file content into a variable and use a regular expression on the variable content.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  bundle agent main
  {
        # CFEngine
        # is the agent you're looking for.

    files:
      "/tmp/example.txt"
        create => "true",
        edit_line => insert_lines( "CFEngine$(const.n)is the agent you're looking for" );

    vars:

        "file_content"
          string => readfile( "/tmp/example.txt" , inf ),
          if => not( isvariable( $(this.promiser) ) );

    classes:

        # Search for a multi-line string
        "I_found_the_agent_i_am_looking_for"
          expression => regcmp( "CFEngine\Ris\sthe\sagent.*",
                                $(file_content));

        "I_did_not_find_droids"
          expression => not( regcmp( ".*droid.*",
                                $(file_content)));


    reports:

        "CFEngine $(sys.cf_version)";

        "/tmp/example.txt contains:$(const.n)$(file_content)";

        "I found the agent i'm looking for."
          if => "I_found_the_agent_i_am_looking_for";

        "I see no droids."
          if => "I_did_not_find_droids";
  }

Results in this output:

R: CFEngine 3.11.0
R: /tmp/example.txt contains:
CFEngine
is the agent you're looking for

R: I found the agent i'm looking for.
R: I see no droids.

You may also want to check out this post about building better regular expressions in CFEngine from Neil Watson.