1

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

range:
    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/"`
echo $TCP_PORT_MIN
# 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`
echo $TCP_PORT_MIN
# 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`
echo $TCP_PORT_MIN
# 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]...

Options:
        -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?

1 Answer 1

2

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.

1
  • 1
    This works exactly as I need. Thanks a lot.
    – Snowjay
    May 29, 2020 at 19:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .