I have a system running on Embedded Linux with BusyBox. There is a YAML configuration file 'cfg.yaml' which contains something like this:

    tcpportmin: 10000
    tcpportmax: 20000

I need to extract some values from the file. For example, the value of the 'tcpportmin' parameter, i.e. '10000'. I do it by means of a script.

When I am executing this piece of code on a small 'cfg.yaml' file everything goes fine:

RANGE=`cat cfg.yaml`
TCP_PORT_MIN=`echo $RANGE | sed "s/.*tcpportmin: \([[:digit:]]*\).*/\1/"`
# Output:
# 10000

But the size of the real 'cfg.yaml' file is several hundreds of kilobytes and in this case an error raises:

/test.sh: line 211: echo: Argument list too long

If I apply the same sed command directly to the file, the result is wrong:

TCP_PORT_MIN=`sed "s/.*tcpportmin: \([[:digit:]]*\).*/\1/" cfg.yaml`
# Output:
# range: 10000 tcpportmax: 20000

If I try to use multiple sed commands in one line, the result is empty:

TCP_PORT_MIN=`sed -e "s/.*tcpportmin: \([[:digit:]]*\).*/\1/" -e "s/.*\([[:digit:]]*\).*/\1/p" cfg.yaml`
# Output:
# <Nothing>

Just for information, the help screen of the sed command on my system:

BusyBox v1.15.3 (2018-08-13 13:52:22 NOVT) multi-call binary

Usage: sed [-efinr] SED_CMD [FILE]...

        -e CMD  Add CMD to sed commands to be executed
        -f FILE Add FILE contents to sed commands to be executed
        -i      Edit files in-place
        -n      Suppress automatic printing of pattern space
        -r      Use extended regex syntax

If no -e or -f is given, the first non-option argument is taken as the sed
command to interpret. All remaining arguments are names of input files; if no
input files are specified, then the standard input is read. Source files
will not be modified unless -i option is given.

My question is: How can I use the sed command to extract values from a file?


The proper way, if you know only one line will match, is

sed -n 's/ *tcpportmin: \([[:digit:]]*\).*/\1/p' cfg.yaml

The -n flag suppresses all output, except those triggered by explicit sed commands, such as p. So, the above sed only outputs lines on which it made a substitution.

You can save the output in a variable with

TCP_PORT_MIN=$(sed -n 's/ *tcpportmin: \([[:digit:]]*\).*/\1/p' cfg.yaml)

Notice that you should favor $() instead of backticks, for readability and nesting.

| improve this answer | |
  • 1
    This works exactly as I need. Thanks a lot. – Snowjay May 29 at 19:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.