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?

  • You can remove the first cat: grep email2 /etc/emails.conf | ... – Carlos Campderrós May 4 '15 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. – Peter Turner May 4 '15 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? – glenn jackman May 5 '15 at 1:25
4

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

  • can it trim the leading space too? – Peter Turner May 4 '15 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 '15 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).

  • Is space required between { s? – cuonglm May 4 '15 at 16:02
  • @cuonglm, no. AFAICT, ;} above is not POSIX but I don't know of any modern sed implementation where that fails. – Stéphane Chazelas May 4 '15 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 '15 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. – Stéphane Chazelas May 4 '15 at 16:23
  • 1
    @PeterTurner, see When should I use input redirection?. – Stéphane Chazelas May 5 '15 at 8:45
3
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]*)
  • 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. – Peter Turner May 4 '15 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 '15 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.