Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash. awk last column with possible spaces

Tags:

bash

awk

I have a dynamic output. Like this sometimes:

F8:XX:94:XX:C2:XX    1    39%     No    ANY_NAME
A2:XX:34:XX:E8:XX    6    42%     Yes    ANY_OTHER_NAME
D1:XX:78:XX:A1:XX    6    24%     No    MORESTUFF

Or like this other times:

F8:XX:94:XX:C2:XX    1    433     39%     No    ANY NAME
A2:XX:34:XX:E8:XX    6    232     42%     No    ANY_OTHER_NAME
D1:XX:78:XX:A1:XX    6    112     22%     Yes    MORE STUFF

As you can see the last column is what I want but it can contain spaces or not and the number of columns is dynamic.

I need to capture the value of the last column always in case of having no spaces or having multiple spaces. Sometimes, the column number is dynamic too but the data I want is always in last place having spaces or not. The column before this data it's always a "Yes" or "No" (not sure if this can help).

Is there a way to do it with awk? This is what I have actually:

myvar=$(echo "${line}" | awk '{print $NF}')

But with this is taking just the last part after a space, not the complete data. So this is working only if the data has no spaces.

What I want is to get always the last data complete with its spaces in case of containing them. Any help?

like image 675
OscarAkaElvis Avatar asked Sep 12 '26 08:09

OscarAkaElvis


2 Answers

If you're sure that the data you care about can never have a run of more than one space then use that as your field separator instead.

awk -F '\t| {2,}' ...
like image 129
Ignacio Vazquez-Abrams Avatar answered Sep 14 '26 07:09

Ignacio Vazquez-Abrams


With GNU awk for \s and \S shorthand:

$ awk '{sub(/[^%]+%\s+\S+\s+/,"")}1' file
ANY_NAME
ANY_OTHER_NAME
MORESTUFF
ANY NAME
ANY_OTHER_NAME
MORE STUFF
oh   No     lots of    spaces

With any awk:

$ awk '{sub(/[^%]+%[[:space:]]+[^[:space:]]+[[:space:]]+/,"")}1' file
ANY_NAME
ANY_OTHER_NAME
MORESTUFF
ANY NAME
ANY_OTHER_NAME
MORE STUFF
oh   No     lots of    spaces

or with any sed that supports -E for EREs (e.g. GNU or OSX/BSD seds):

$ sed -E 's/[^%]+%[[:space:]]+[^[:space:]]+[[:space:]]+//' file
ANY_NAME
ANY_OTHER_NAME
MORESTUFF
ANY NAME
ANY_OTHER_NAME
MORE STUFF
oh   No     lots of    spaces

The above was run on this input file:

$ cat file
F8:XX:94:XX:C2:XX    1    39%     No    ANY_NAME
A2:XX:34:XX:E8:XX    6    42%     Yes    ANY_OTHER_NAME
D1:XX:78:XX:A1:XX    6    24%     No    MORESTUFF
F8:XX:94:XX:C2:XX    1    433     39%     No    ANY NAME
A2:XX:34:XX:E8:XX    6    232     42%     No    ANY_OTHER_NAME
D1:XX:78:XX:A1:XX    6    112     22%     Yes    MORE STUFF
D1:XX:78:XX:A1:XX    6    112     22%     Yes    oh   No     lots of    spaces

wrt your comments, here is the first script handling the input file contents being passed to it 1 line at a time from a pipe:

$ while IFS= read -r line; do
    echo "$line" | awk '{sub(/[^%]+%\s+\S+\s+/,"")}1'
done < file
ANY_NAME
ANY_OTHER_NAME
MORESTUFF
ANY NAME
ANY_OTHER_NAME
MORE STUFF
oh   No     lots of    spaces

All of the other scripts can be used exactly the same way.

like image 41
Ed Morton Avatar answered Sep 14 '26 07:09

Ed Morton