6

Say I had a config file /etc/emails.conf

email1 = user@dinkum.dorg 
email2 = user@winkum.worg
email3 = user@stinkum.storg

and I wanted to get email2

I could do a:

grep email2 /etc/emails.conf | cut -d'=' -f2 

to get the email2, but how do I do it "cooler" with one sed or awk command and remove the whitespace that the cut command would leave?

3
  • You can remove the first cat: grep email2 /etc/emails.conf | ... May 4, 2015 at 15:59
  • @CarlosCampderrós dang, I had thought I tried that but it failed for some completely unknown hidden reason (because obviously it should have worked). I just put the file name at the end of the cut wrongly and that's why it didn't work. I revised the question, I don't think it invalidates the answers. May 4, 2015 at 16:20
  • I really don't understand your question: you already have the string that you're searching for: result="email2" -- what are you really trying to do? May 5, 2015 at 1:25

5 Answers 5

5

How about using awk?

awk -F = '/email2/ { print $2}' /etc/emails.conf
  • -F = Fields are separated by '='

  • '/email2/ { print $2}' On lines that match "email2", print the second field

2
  • can it trim the leading space too? May 4, 2015 at 16:23
  • 1
    @PeterTurner, my version of awk permits -F ' *= *', which is a wildcarded expression that groups spaces either side of = as part of the separator.
    – roaima
    May 4, 2015 at 19:32
4

The exact equivalent would be something like:

sed -n '/email2/{s/^[^=]*=\([^=]*\).*/\1/;p;}' < file

But you'd probably want instead:

sed -n 's/^[^=]*email2[^=]*=[[:blank:]]*//p' < file

(that is match email2 only on the part before the first = and return everything on the right of the first = (skipping leading blanks), not only the part up to the second = if any).

14
  • Is space required between { s?
    – cuonglm
    May 4, 2015 at 16:02
  • @cuonglm, no. AFAICT, ;} above is not POSIX but I don't know of any modern sed implementation where that fails. May 4, 2015 at 16:08
  • Yes, that's exactly I have stucked when working with this. After re-reading POSIX sed documentation, I see ;} is an accepted extension, but it's not required. It's strange that GNU sed with --posix option still allow {command} form. Do you think it's a bug?
    – cuonglm
    May 4, 2015 at 16:12
  • 1
    @cuonglm {command} is not required to report an error by POSIX. It's just that a POSIX script must not use it as the behaviour is not specified there. Where GNU sed is not conformant even with --posix is that it doesn't accept ; in label names. May 4, 2015 at 16:23
  • 1
    @PeterTurner, see When should I use input redirection?. May 5, 2015 at 8:45
2
perl -nlE 's/email2\s*=\s*// and say'    file

Where:

  • perl -nl is a for each line do...
  • s/email2 = // removes the searched email id and if you could do it ...
  • say prints the current input input line
  • \s* zero or more spaces (equivalent to [ \t\n]*)
2
  • I'll give you a +1 for golfing, but where I'm running this (some sort of stripped down Cisco appliance), I'm not sure I'm going to have perl, especially the version of perl that has say. May 4, 2015 at 17:51
  • perl 5.10 appeared 7 year ago but sometimes we don't have it... perl -nle 's/email2\s*=\s*// and print'
    – JJoao
    May 4, 2015 at 17:59
0

There is no need to set the field separator to any special value such as "=". By default, AWK uses contiguous spaces and tabs as field separators, which are skipped, so it will interpret each line of your file as having three fields, without any leading space on field three

awk '/^email2/ { print $3 }'

produces

user@winkum.worg

The above would also match any lines starting with email2, such as email20, for exact match you can use

awk '$1 == "email2" { print $3 }'
0

To get something like grep | cut you can use sed -n s/A/B/p.

By default, sed prints every line after all commands are processed. You can silence all output that you don't explicitly print from a command with sed -n.

The s command takes the form s/$FIND/$REPLACE/$FLAGS. Specifically, the p flag prints the line whenever a replacement is made.

With these combined, you can easily match and cut:

sed -nE "s/email2 = (.+)/\1/p" < /etc/emails.conf

In fact, this is strictly more powerful than grep | cut because you can use an arbitrary replacement pattern.

(The -E option enables modern regex, which allows you to reference capture groups in the replacement pattern. For a simple cut, you can get away without it by using more clever patterns.)

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.