5

I have a file that looks like this:

asd 123 aaa wrqiqirw 123
123 itiewth 123 asno 123
123 132 123 123 123
boagii 123 asdnojaneoienton 123

Expected output is:

123
123
123
123

I will need to search for patterns via regex. Is there any way to implement such a thing?

  • 2
    Most programs that deal with regular expressions print the first match by default. What regex will you be using? The example of 123 is too trivial to be useful. – terdon Mar 15 '17 at 10:01
  • 2
    @terdon strictly speaking, it's not printing the first match, but do something with the first match. – cuonglm Mar 15 '17 at 10:18
  • 1
    What do you expect for lines without a matching pattern? – Philippos Mar 15 '17 at 12:21
7

With pcregrep, with a pattern like 12*3:

pcregrep -o1 '(12*3).*'

With pcregrep or GNU grep -P:

grep -Po '^.*?\K12*3'

(pcregrep works with bytes more than characters, while GNU grep will work on characters as defined in the current locale (and you'd have to make sure the input contains valid text in the current locale)).

Note that GNU grep won't print anything if the pattern matches the empty string.

3
sed -e '
   /\n/{P;d;}
   s/12*3/\n&\n/;D
' < inoutfile
  • This is gnu sed only fwiw... – don_crissti Mar 15 '17 at 13:38
3

In Perl, simply

perl -lne 'print $& if /\d+/' inputfile

or from stdin:

echo foo 123 bar 456 doo 789 | perl -lne 'print $& if /\d+/'
123

The regex \d+ will match any string of consecutive numbers, and $& refers the matching string.

3

POSIXLY:

LC_ALL=C sed -e 's/.*\(123\).*/\1/' <file

LC_ALL-C is needed here to prevent sed from crashing or producing unexpected result if the file contained invalid characters in your current locale.

It also produces one entry at a line, but matched the last, not the first.

For matching the first, with GNU sed and PCRE:

LC_ALL=C sed -E 's/.*?(123).*/\1/'

(-E for extended RE will be in next version of POSIX)

  • Note that this will catch the last 123 on the line and not the first. – user218374 Mar 15 '17 at 10:52
  • @RakeshSharma Yes, of course, not sure why my editing was not updated, Fix it now – cuonglm Mar 15 '17 at 10:57
  • 3
    EREs don't have the *? operator. You need perl or compatible regexps for that. – Stéphane Chazelas Mar 15 '17 at 11:42
  • 1
    I don't get your last edit... There is no sed that supports PCRE and -E stands for extended regex aka ERE which, as noted above, doesn't support the *? operator. – don_crissti Mar 15 '17 at 13:36
  • 1
    As such, the second solution will still print the last match... – don_crissti Mar 15 '17 at 13:42
3

Just a grep should be enough to bring matches of 123 in every line.
It does not makes sense if the match is first ,middle or in the end.
You ask for 123 you get 123 if it is in the line (unless your question is not expressed correctly and you require something different)

$ grep -wo '123' file # -w: word match  -o : return only matched string instead of the whole line (default grep operation)

In case you need to catch with regex the first number of each row (any number - any length) then this will do the job:

cat <<EOF >file1
asd 111 777 aaa wrqiqirw 123
333 123 itiewth 123 asno 123
4444 111 123 123 567
boagii what 666 asdnojaneoienton 123
EOF
grep -Po '^[0-9]+|^.*?\K[0-9]+' file1
#output
111
333
4444
666
  • Actually this will just print the first match and quit. It's a first match/file rather than /line. – user218374 Mar 15 '17 at 11:03
  • @RakeshSharma Yes, corrected – George Vasiliou Mar 15 '17 at 11:10
  • @Andrew Updated again. Will match first number of each line (of any length.) – George Vasiliou Mar 15 '17 at 12:13
  • Actually the first one is covered by the second since you are in Perl mode so this should suffice: grep -oP '^.*?\K\d+' – user218374 Mar 15 '17 at 12:16
2

With grep in every line:

while IFS= read -r line; do printf '%s\n' "$line" | grep -o 123 | head -1; done < filename

That is:

  • While loop in order to check each line separately.
  • grep -o to get only the match instead of the whole line with matches.
  • head -1 to take only the first match and not the following ones.
  • 3
    You should avoid using while loop to process text in shell script, see unix.stackexchange.com/q/169716/38906. Also, you have to double quote your variable, and using printf instead of echo. – cuonglm Mar 15 '17 at 10:39
1

with awk

re='12*3' awk '{match($0, ENVIRON["re"])}; RSTART{print(substr($0, RSTART, RLENGTH))}' file

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.