Skip to main content

patternMatches

patternMatches(config: List<ConfigLine>, pattern: Pattern<T>) : Bag<{line: ConfigLine, data: T}>

Matches pattern against the text of each config line in config and returns one record for each line that matches. Lines that do not match are omitted. If no line matches, the result is an empty bag.

Each record has the following fields:

  • line: ConfigLine The matching config line.
  • data: T The data extracted by the pattern, as returned by patternMatch.

The result is a Bag, so the records have no defined order.

See Details on Patterns for the full pattern syntax.

Matching rules​

  • Each line is matched with the same rules as patternMatch. See patternMatch matching rules.
  • Only the lines in config are matched. The children of those lines are not searched. Pass match.line.children to a second patternMatches call to match nested lines (see Matching nested lines).
  • null items in config are skipped.

Null inputs​

If config or pattern is null, the query fails with the error First argument to “patternMatches” was null; consider adding an isPresent() condition. (or Second argument for pattern). The config field of a device's files is nullable. Use isPresent to exclude null values before calling patternMatches.

Examples​

The first column lists the text of each line in config, in order.

The text of each line in configpatternThe data of each matchRemarks
"interface Ethernet1/1",
"interface Ethernet1/2"
`interface {name:string}`{name: "Ethernet1/1"},
{name: "Ethernet1/2"}
Each matching line produces one record in the result.
"hostname r1",
"ntp server 10.0.0.1",
"ntp server 10.0.0.2"
`ntp server {server:ipv4Address}`{server: 10.0.0.1},
{server: 10.0.0.2}
Lines that do not match, such as hostname r1, are omitted from the result.
"hostname r1",
"feature bgp"
`ntp server {server:ipv4Address}`No matchesIf no line matches, the result is an empty bag.
"feature bgp",
"feature ospf"
`feature bgp`{}A pattern with no components extracts no data. Use it to find lines with a given form; the line field of each record holds the matching line.
"shutdown",
"no shutdown"
`shutdown`{}The pattern must match at the start of each line. no shutdown does not start with the literal shutdown, so only the first line matches.
"logging host 10.0.0.1",
"logging host 10.0.0.1 vrf mgmt"
`logging host {host:ipv4Address} {eof}`{host: 10.0.0.1}{eof} requires the pattern to match the whole line. The second line has the text vrf mgmt after the address, so it does not match.

You can try out any of these examples by copying the lines and pattern above into the following query template:

lines = [...];

pattern = ...;

config = parseConfigBlocks(OS.IOS, join("\n", lines));

foreach match in patternMatches(config, pattern)
select { data: match.data }

Example query​

The following query lists the TACACS servers configured on each device, along with the text of the matching config line.

foreach device in network.devices
where isPresent(device.files.config)
foreach match in patternMatches(device.files.config, `tacacs-server host {server:string}`)
select {device: device.name, tacacsServer: match.data.server, line: match.line.text}

patternMatches returns a bag, so the query uses a foreach qualifier to iterate over the matches. Lines that do not match the pattern are not in the bag, so the query needs no isPresent check on each match, unlike a query that uses patternMatch.

Matching nested lines​

Use the children field of a matching line to match the lines nested under it. The following query lists the speed of each interface on Cisco NX-OS devices. The first patternMatches call matches the top-level interface lines, and the second call matches the speed lines nested under each interface.

foreach device in network.devices
where device.platform.vendor == Vendor.CISCO && device.platform.os == OS.NXOS
&& isPresent(device.files.config)
foreach ifaceMatch in patternMatches(device.files.config, `interface {iface:string}`)
foreach speedMatch in patternMatches(ifaceMatch.line.children, `speed {speed:number}`)
select {device: device.name, iface: ifaceMatch.data.iface, speed: speedMatch.data.speed}

Calling patternMatches(device.files.config, `speed {speed:number}`) directly returns no matches for this configuration, because the speed lines are children of the interface lines, not top-level lines.

Deprecated Bag overload

patternMatches also accepts a Bag<ConfigLine> as its first argument. A Bag has no defined order, so this overload produces a warning. Use orderBy() or order() to convert the argument to a List<ConfigLine>. In a future release, the warning will become a type-checking error.

The blockMatches builtin provides an alternative method for matching multiple, nested lines of configuration, and is often easier to use than patternMatches. For instance, the example above can be expressed more succinctly using blockMatches as follows:

blockPattern = ```
interface {iface:string}
speed {speed:number}
```;

foreach device in network.devices
where device.platform.vendor == Vendor.CISCO && device.platform.os == OS.NXOS
&& isPresent(device.files.config)
foreach match in blockMatches(device.files.config, blockPattern)
select { device: device.name, iface: match.data.iface, speed: match.data.speed }

Prefer using blockMatches to match nested lines, unless you need more control over the matching logic than is provided by block patterns.

See also​

Guides​

Types​

Functions​

  • patternMatch: Matches a pattern against a single string, and returns the extracted data or null.
  • blockMatches: Matches a block pattern against nested config lines.
  • parseConfigBlocks: Parses a string that holds a device configuration into a list of config lines.