32

I want to read one part of one line from a file. For example:

POP3_SERVER_NAME = localhost

I want to return only localhost, using sed.

This text is on the third line. I do this to extract the line:

sed -n '3p' installation.sh

How do I extract only the localhost part?

7 Answers 7

44

awk might be a better tool here.

$ cat test.dat
LINE 1
LINE 2
POP3_SERVER_NAME = localhost

Search for lines that contain "POP3_SERVER_NAME"; print the last field. This doesn't depend on POP3_SERVER_NAME always being on line 3, which is probably a Good Thing.

$ awk '/POP3_SERVER_NAME/{print $NF}' test.dat
localhost

Depending on your application, you might need to make the regular expression more stringent. For example, you might want to match only that line that starts with POP3_SERVER_NAME.

$ awk '/^POP3_SERVER_NAME/{print $NF}' test.dat
localhost

Using sed is a little less intuitive. (Thanks, I'm aware of the irony.) Address the line that contains POP3_SERVER_NAME anywhere. Substitute an empty string for all the text from the beginning of the line to the optional space following "=". Then print.

sed -n -e '/POP3_SERVER_NAME/ s/.*\= *//p' test.dat
5
  • 5
    The awk command is nice - but only if you've got spaces around the =. It won't work for POP3_SERVER_NAME=localhost. Commented Feb 14, 2016 at 11:07
  • 6
    @Marcel, You can change the delimiter used by awk from spaces to something else using -F. For instance: -F "=" will use = as a delimiter in the case you mention.
    – mattpr
    Commented Apr 11, 2018 at 7:44
  • How can I print the value of a capture group with awk? For example, I expected something like awk '/POP3_SERVER_NAME = (.*)/ { print \1 }' test.dat Commented May 28, 2021 at 23:06
  • What is the second * for in the sed cmd? The first is for zero or more chars.
    – Timo
    Commented Oct 18, 2021 at 7:27
  • 1
    @Timo: The second * here means to match zero or more spaces following =. So it will print localhost given =localhost, = localhost, or = localhost. That seemed like a careful way to use sed here. Commented Oct 18, 2021 at 10:05
9

Replace the p command by a substitution that removes the unwanted part of the line.

sed -n '3 s/^[^=]*= *//p' installation.sh

You may want to match the line by keyword rather than by position.

sed -n 's/^ *POP3_SERVER_NAME *= *//p' installation.sh
7

Looks like you've got a config file. What you could do is similar to what Adam Siemeon/slm suggest:

sed -nr 's/[^=]+=\s*(.+)$/\1/p' filename

where [^=] excludes all '=' characters, + says one or more of the same type of character, this followed by an actual =, \s any whitespace (including tabs \t and new lines \n, \r\n, and plain spaces ' ', whereas * means zero or more of the same type, parentheses catch what's inside to place the matched character sequences into the \1, \2, ..., \n replacement placeholders, $ means the end of a line. This follows the typical replacement pattern of: s/.../.../modifiers. The command line option -r stands for extended regex syntax (as a matter of convenience) and -n means output nothing until or unless explcitly requested. The p modifier prints out the result.

You could make a global search with the g modifier like:

sed -nr 's/[^=]+=\s*(.+)$/\1 /pg' filename  # note the space after \1

so that you get a string separated by ' ' (could be \n, \t, or what have you) which you can process easily.

Both is valid provided your values preceded by the equation character span up to the end of a line and are not followed by comments or other characters with semantics deviating from a simple "value".


Edit:

I can't comment here yet on other's posts. To indicate the line just pass the line number, in your case 3, before s or before the initiating quote char (just like in vim).

sed -nr '3s/[^=]+=\s*(.+)$/\1/p' filename

Please take a look at info sed. For example, 3.2 and 4.7 are of particular interest to you.

6

You can use the cut command, setting the delimeter to '=' and then print the second field like this:

cut -d'=' -f2
5
echo "POP3_SERVER_NAME = localhost" | sed 's/.*= //'
localhost

Or if you have the contents in a file:

sed 's/.*= //' somefile.txt
localhost
3
  • ok, but i read in my file like this: sed -n '3p' installation.sh
    – Mercer
    Commented Jul 30, 2013 at 15:21
  • 2
    @Mercer - see the updates I added to the answer.
    – slm
    Commented Jul 30, 2013 at 15:25
  • @Adam Siemion - thank you, but how to indicate the line number?
    – Mercer
    Commented Jul 30, 2013 at 15:27
5

The beauty of Linux/Unix is that there is usually more than one way to accomplish something. In the op's case, there are at least four different ways to extract the POP server name from the file:

  1. grep POP3_SERVER_NAME installation.sh | cut -d'=' -f2
  2. grep POP3_SERVER_NAME installation.sh | awk '{print $3}'
  3. grep POP3_SERVER_NAME installation.sh | sed 's/.*= //'
  4. sed -n 's/^.*POP3_SERVER_NAME = //p' installation.sh
3

Multiple ways to do it, considering your file is called foobar:

Specify the pattern to search for:

PAT=POP3_SERVER_NAME

Extract using sed

sed -n "/$PAT/p" foobar | sed "s/$PAT = //"

Or using sed and cut

sed -n "/$PAT/p" foobar | cut -d' ' -f3

You must log in to answer this question.

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