Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWK regex split function using multiple delimiters

Tags:

regex

awk

I'm trying to use Awk's split function to split input into three fields in order to use the values as field[1], field[2], field[3]. I'm trying to extract the first value: everything (including) the colon, then everything until the first tab (\t) (the hex), then the last field will include everything else.

I've tried multiple regexes and the closest I've come to solving this is:

echo -e "ffffffff81000000: 48 8d 25 51 3f 60 01\tleaq asdf asdf asdf" \
| awk '{split($0,field,/([:])([ ])|([\t])/); \
print "length of field:" length(field);for (x in field) print field[x]}'

But the result doesn't include the colon --and I'm not sure if it's good regex I've written:

length of field:3
ffffffff81000000
48 8d 25 51 3f 60 01
leaq asdf asdf asdf

Thanks in advance.

like image 304
Zeteroo Avatar asked Jul 23 '26 03:07

Zeteroo


2 Answers

Using gnu-awk's RS (for record separator) variable:

s=$'ffffffff81000000: 48 8d 25 51 3f 60 01\tleaq asdf asdf asdf'
awk -v RS='^\\S+|[^\t:]+' '{gsub(/^\s*|\s*$/, "", RT); print RT}' <<< "$s"

ffffffff81000000:
48 8d 25 51 3f 60 01
leaq asdf asdf asdf

Explanation:

  • RS='^\\S+|[^\t:]+': Sets RS as 1+ non-whitespace characters at the start OR 1+ of non-tab, non-colon characters
  • gsub(/^\s*|\s*$/, "", RT) removed whitespace at the start or end from RT variable that gets populated because of RS
  • print RTprintsRT` variable

If you want to print length of fields also then use:

awk -v RS='^\\S+|[^\t:]+' '{gsub(/^\s*|\s*$/, "", RT); print RT} END {print "length of field:", NR}' <<< "$s"

ffffffff81000000:
48 8d 25 51 3f 60 01
leaq asdf asdf asdf
length of field: 3

If you don't have gnu-awk then here is a POSIX awk solution for the same:

awk '{
   while (match($0, /^[^[:blank:]]+|[^\t:]+/)) {
      print substr($0, RSTART, RLENGTH)
      $0 = substr($0, RSTART+RLENGTH)
   }
}' <<< "$s"

ffffffff81000000:
 48 8d 25 51 3f 60 01
leaq asdf asdf asdf
like image 142
anubhava Avatar answered Jul 25 '26 00:07

anubhava


Using your awk code with some changes:

echo -e "ffffffff81000000: 48 8d 25 51 3f 60 01\tleaq asdf asdf asdf" | awk -v OFS='\n' '
{
sub(/: */,":\t")
split($0,field,/[\t]/)
print "length of field:" length(field), field[1], field[2],field[3]
}'
length of field:3
ffffffff81000000:
48 8d 25 51 3f 60 01
leaq asdf asdf asdf

As you can see:

  • added a tab with sub(),
  • so the separator for split() is only [\t],
  • and the OFS is \n.
  • And finally only a print.
like image 36
Carlos Pascual Avatar answered Jul 25 '26 00:07

Carlos Pascual



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!