7 ms·
I wish Awk had capture groups. It would fit in so well with typical Awk one-liners to be able to say: awk '/foo=([0-9]+)/ { print $1 }' although I suppos
by comex 4y ago
I wish Awk had capture groups. It would fit in so well with typical Awk one-liners to be able to say:
awk '/foo=([0-9]+)/ { print $1 }'
although I suppose the syntax would have to be different since $1 has a meaning already.
Yes, gawk has a function that returns capture groups, but it's a bit verbose for one-liners. Instead I switch to Perl:
perl -nE 'if (/foo=([0-9]+)/) { say $1 }'
But I wish I could just use Awk.
- _TwoFinger 4y agoYou can still do it with awk, but with different "ergonomics": awk -F= '$2 ~ /[0-9]+/ { print $2 }' With imaginative choice of FS and RS you can push it very far. Whether other people having to deal with such code will appreciate your imagination is another matter, though. Edit: I missed the detail where you want to specifically match "foo" as lhs, and anywhere on the line. So the correct condition would be even lengthier : ^ ) You have a valid point. Captures would provide for shorter patterns.
- forinti 4y agoI wish grep had capture groups so I could do things like grep "\((\d+)\)" -print "$1" file.txt
- defrost 4y agoripgrep is a modern faster grep in Rust, some cons, many pros. It'll do capture groups with search | replace # remove square brackets that surround digit characters $ echo '[52] apples [and] [31] mangoes' | rg '\[(\d+)]' -r '$1' 52 apples [and] 31 mangoes
- asicsp 4y agoPleasantly surprised to see an example from my ebook :) Add `-o` option to get only the digits: $ echo '[52] apples [and] [31] mangoes' | rg -o '\[(\d+)]' -r '$1' 52 31
- defrost 4y agoCongratulations (?) for making the top five google results for "ripgrep capture groups" [1]. I cite sources way more often than not, this time I got lazy after dithering over whether to go with the definitive ripgrep source page [2] or a decent looking third party(?) tutorial .. pressed for time I did neither. [1] https://learnbyexample.github.io/learn_gnugrep_ripgrep/ripgrep.html https://learnbyexample.github.io/learn_gnugrep_ripgrep/ripgr... [2] https://github.com/BurntSushi/ripgrep https://github.com/BurntSushi/ripgrep
- asicsp 4y agoIf PCRE is supported: grep -oP '\(\K\d+(?=\))' The above will give all matches in a line though. You can remove `(?=\))` part if numbers are always enclosed in `()` or if you don't care about the `)`
- sargstuff 4y ago[1] gives some background about the issue and possible solution(s). [1] : https://unix.stackexchange.com/questions/536657/how-to-refer-to-a-regex-group-in-awk-regex https://unix.stackexchange.com/questions/536657/how-to-refer...
- asicsp 4y agoI don't use `match` often, so I get the `match(str, regex)` order wrong. So yeah, it would be nice if gawk automatically provided the capture groups via some special variable. Not really verbose for this particular example though: $ echo 'foo=42' | awk 'match($0, /foo=([0-9]+)/, m){print m[1]}' 42 $ echo 'foo=42' | perl -nE 'if (/foo=([0-9]+)/) { say $1 }' 42 # TIMTOWTDI $ echo 'foo=42' | perl -nE 'say $1 if /foo=([0-9]+)/' 42
- iso1631 4y agoI have to admit I never really learned awk, but whenever I want to do something that I think "awk would be god for this", I use perl. Are there things for which awk is a significantly better tool?
- sargstuff 4y agoIdeal for embedded systems where resources are limited.
- sargstuff 4y agoGNU Awk version 5 has dynamic regexprs. [1] [1] 3.6 using Dynamic Regexps : https://www.gnu.org/software/gawk/manual/html_node/Computed-Regexps.html https://www.gnu.org/software/gawk/manual/html_node/Computed-...
- kazinator 4y agoI recently saw someone on StackOverflow asking for something similar: access, from the condition-action body, to the text which matched the regex. So I added a feature to the TXR Lisp awk macro. There is now an Awk variable called res which holds the result of the condition. If the condition is a regex, then that has the matching part. The fact that the action is executing tells us that the result of the condition is true; but res gives us the specific true value, like the it in anaphoric if macros. This made it into release 284.
- 1vuio0pswjnm7 4y agoCan use sed. One way is to use a "sentinal", for example, a non-printable character that is absent from the input. sed -n "s/SENTINAL//g;s/\(.*\)\(foo=\)\([0-9]*\)\(.*\)/SENTINAL\3/;/SENTINAL/!d;s/SENTINAL//;/./p" shortened to x=$(echo x|tr x '\34'); sed -n "s/$x//g;s/\(.*\)\(foo=\)\([0-9]*\)\(.*\)/$x\3/;/$x/!d;s/$x//;/./p" Using flex is another option. Faster than AWK, Perl, sed and similarly ubiqitous. flex -8iCrf -o/dev/stdout << eof|cc -xc -O3 -std=c89 -pedantic -W -Wall -static /dev/stdin int fileno(FILE *); #define J BEGIN #define E ECHO int x; %option noyywrap noinput nounput %s x1 x2 %% foo=[^\n] yyless(1);J x1;x++; <x1>[0-9]+ if(x==1)E;J x2; <x2>\n E;x=0;J 0; <x2>. .|\n %% int main(){ yylex();exit(0);} eof