9

I have this file

1 deiauk David Smith from California 12 58
2 edvin from Nevada 12 5 8 95 2 48 5
3 jaco My Name Is Jacob I'm from NY 5  6  845 156 585
4 from Miami

And I need to get values after specific word from is it possible to do that in shell? My output should be

California
Nevada
NY
Miami

5 Answers 5

20

Using grep, it can be done as follows:

grep -oP "from\s+\K\w+" input.txt

Here,

-o  ==>  option for printing only the matching part of the line
-P  ==>  use perl-regexp
\K  ==>  do not print that comes before \K (zero-width look-behind assertion)
\w  ==>  match word characters
3
  • Wow, that look behind assertion looks way easier than vim's. Does Perl subscribe to a standard RegEx (if there is such a thing) or is it just a lot easier to understand? Jun 2, 2015 at 22:50
  • 1
    @user1717828 I don't know what RegEx Perl subscribes to, but the cheat-sheet I have with me is based on Perl regex. Moreover, perl regex is more powerful than the basic and extended RegEx.
    – shivams
    Jun 2, 2015 at 22:56
  • @user1717828, that's not a look-behind assertion, it sets the start of the matched portion, so it can replace a look-behind assertion (here the Perl/PCRE look behind assertion would be (?<=from\s+), except that in perl (contrary to vim's \v(from\s+)\@<=) look-behinds can only be of fixed length so wouldn't work) Nov 28, 2016 at 9:29
12

Or:

awk '{for (I=1;I<NF;I++) if ($I == "from") print $(I+1)}' file
1
  • Kindly, how can this command output five words or numbers after "from"?
    – user88036
    May 12, 2017 at 0:26
8

A readable solution would be:

awk -F '${fixed_string}' '{print $2}' file | awk '{print $1}'

What it does:

  • -F '${fixed_string}' separates the input into before and after the given string. So with your file, when we set fixed_string='from', print $2 would give:

    California 12 58 Nevada 12 5 8 95 2 48 5 NY 5 6 845 156 585 Miami

  • Now, all you need is the 1st column of this input. So we pipe the output of the first awk to awk and print the 1st column.

4
  • Could you describe a bit more about what's going on here? Why would ${fixed_string} be a good field separator, for example, and why do you pipe the output of awk through awk again?
    – Kusalananda
    Aug 15, 2017 at 18:47
  • @Kusalananda Honestly, I couldn't figure out a readable solution to do it using just one awk. Aug 15, 2017 at 22:52
  • Point for idea of using the match word as the separator. Easy to remember. @Jignesh Darji I'm not sure what the ${} is for around fixed_string?. Mine worked by simply using awk -F 'from' ... format. Nov 18, 2019 at 10:27
  • awk is awesome, thanks for this simple and easy solution!
    – Kay
    Dec 14, 2021 at 18:56
1

This sed one liner does it:

 sed '/from/s/.*from \([^ ][^ ]*\)[ ]*.*/\1/' input

I'm presuming a space character before the "from" literal string. If you want to have tab-separated fields, you might have to insert a tab-character in all three character-range-match expressions, those between '[' and ']'.

2
  • It will get the last - but it might strip other froms in doing so.
    – mikeserv
    Jun 3, 2015 at 5:10
  • 1
    Just an improvement after removing some redundancies sed 's/.*from \([^ ]*\)[ ]*.*/\1/' input Aug 16, 2017 at 1:06
1

Assume the file name is test.txt

$ cat test.txt
deiauk David Smith from California 12 58
edvin from Nevada 12 5 8 95 2 48 5
jaco My Name Is Jacob I'm from NY 5  6  845 156 585
from Miami

You can use sed to grep everything after from then cut the output like this.

$ cat test.txt | sed 's/.*from //' | cut -d " " -f 1
California
Nevada
NY
Miami

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.