VyOS Platform Blog

Building an open source network OS for the people, together.

Pipes in VyOS CLI

Posted 21 Jan, 2021 by Erkin Batu Altunbas

Unix pipes are an indispensable tool on a sysadmin’s belt. Eventually, it becomes second nature to build a pipeline of several tools to transform data and one often feels frustrated when they can’t use it in a CLI environment distinct from a Unix shell.

VyOS CLI is a high-level, centralized interface where the great variety of configurable subcommands often eschews the need to pipe multiple small programs together to shape the output into the desired form. (Although, you still can do that, naturally.) However, there are cases where one feels the need of generic functions that can be applied to the output of any subcommand.

You might be surprised to hear that VyOS CLI does, in fact, come with its own pipe functionality and a smart one at that. Instead of distinct programs, VyOS CLI provides pipe functions that are explicitly intended for this purpose. Such functions can be tab-completed and the CLI will only suggest pipe functions that would make sense in the context of the preceding command. This functionality is, unfortunately, not very well known, as the subcommands tend to cover most cases, but once you see how convenient pipe functions are, you’ll find yourself writing your own to cover your project’s needs.

Let’s cut to the chase and illustrate pipes with a few examples, starting with the simplest, yet most commonly used functions, then move on to more complex ones.

more and no-more

more displays the piped text in a pager for reading, whereas no-more overrides the subcommand’s default behaviour of using a pager by directly printing the output.

match and no-match

As the name suggests, match, put simply, matches text from piped input according to the specified regular expression pattern. no-match does the opposite, discarding matching lines. These pipe functions use POSIX extended regular expressions by default.

# show firewall | match ipv6
 ipv6-receive-redirects disable
 ipv6-src-route disable


count simply prints the number of lines in the piped input and discards the text itself. Naturally, you can chain all pipe functions.

$ show conntrack table ipv4 | match udp | count

Moving on...


Sometimes, you need to save the output of a command in a publicly accessed place or share it with others who don’t have the credentials to see parts of the output containing sensitive information. Instead of manually going through the output line by line, trying to spot confidential data to scrub each time, you can just use the strip-private function to sterilise the text. We’re going to use it in the next examples.

$ show arp | match '.101.' | match 'eth3' | strip-private
xxx.xxx.101.79            ether   XX:XX:XX:XX:XX:36   C                     eth3
xxx.xxx.101.254           ether   XX:XX:XX:XX:XX:60   C                     eth3

The following two functions can only be used in conf mode, as they don’t make sense in an op mode context. Don’t forget to commit your changes before using them, although they will warn you either way.


You might often find yourself trying to replicate an existing configuration. Instead of directly fiddling with config files or manually writing out op mode commands from conf mode output, you can ask the CLI to convert the config to op mode commands.

Consider the following configuration:

# show protocols bgp | strip-private
 bgp XXXXXX {
     address-family {
         ipv4-unicast {
             network xxx.xxx.16.0/21 {
     neighbor xxx.xxx.34.1 {
         address-family {
             ipv4-unicast {
                 route-map {
                     export LocalOnly
         remote-as XXXXXX

To obtain the commands that produced this config, we can simply use commands:

# show protocols bgp | commands | strip-private
 set bgp XXXXXX address-family ipv4-unicast network xxx.xxx.16.0/21
 set bgp XXXXXX neighbor xxx.xxx.34.1 address-family ipv4-unicast route-map export 'LocalOnly'
 set bgp XXXXXX neighbor xxx.xxx.34.1 remote-as '64840'


The HTTP API takes configuration in the form of JSON payloads. To make it easier to prepare JSON data, json converts Unix-style config syntax into JSON. Note that this pipe function is going to be included in the upcoming release, although it’s considered for a backport as of v1.2.6. You can try it in the current rolling release.

Again, consider the following configuration.

# show system syslog
 global {
     facility all {
         level info
     facility protocols {
         level debug

It's trivial to convert it to JSON as such.

# show system syslog | json
    "global": {
        "facility": {
            "all": {
                "level": "info"
            "protocols": {
                "level": "debug"

Of course, you can also use JSON processors like jq with it.

# show system syslog | json | jq '.global.facility.all.level'

That wraps up the pipe functions currently in VyOS CLI. I hope you’ll find them useful.