3

When changing a field in awk, the whole string ($0) will be split and reformatted with OFS (default <space>). How can I suppress or change that behavior, thus preserving the formatting?

For example, df -h outputs a table where fields (columns) are separated by one or more tabs and space(s). I want all usage values (field #5) >= 80% to be printed in bold red and preserve the structure of the table:

df -h | awk '{ if($5 ~ /^[8-9][0-9]/) $5="\033[1;31m"$5"\033[0m"; print $0 }'

The string will be reformatted with OFS=' ' thus breaking the formatting of the output table. Using -v OFS='\t'

df -h | awk -v OFS='\t' '{ if($5 ~ /^[8-9][0-9]/) $5="\033[1;31m"$5"\033[0m"; print $0 }'

will place tabs where only a few spaces are needed to reach the next column. Forcing to reformat each and every line with else {$5=$5}:

df -h | awk -v OFS='\t' '{ if($5 ~ /^[8-9][0-9]/) {$5="\033[1;31m"$5"\033[0m"} else {$5=$5}; print $0 }'

will still break the table structure in cases where more tabs and spaces are needed to reach the column.

3 Answers 3

2

another trick is to force awk's field separator to use "single space" as field separator by defining it as regex like -F'( )', and perform the modification on Use% column counting down from the end of the line to $(NF-1), since last two columns always separated with single space, so it's easy to catch second last column by $(NF-1) like.

df -h \
| awk -F'( )' '$(NF-1) ~ /^([5-9][0-9]|100)/ { $(NF-1)="\033[1;31m"$(NF-1)"\033[0m" }1'

well, you could also use grep as following:

df -h |grep -P '([5-9][0-9]|100)%(?=\s+/)|' --color
4
  • Very inspirational! I learned something and updated my answer accordingly. The round brackets in the regex seem to be optional, true? Though I see how the -F'( )' with the round bracket works, I can't find an explanation, documentation or tutorial on it.
    – jamacoe
    Jun 18, 2020 at 13:12
  • if you mean parenthesis in ^([5-9][0-9]|100), yes, here because df controls its output so it could be removed, even ^ as well, however it's input dependent which here doesn't make sense. -F'( )' has no specific documentation since it's from the main subject to "FS as regular expression". at the end, if you were happy with answer above, please take your time and read What should I do when someone answers my question?. thanks Jun 18, 2020 at 13:28
  • -F'[ ]' will also work instead of -F'( )'
    – fpmurphy
    Jun 18, 2020 at 16:45
  • @fpmurphy anything that make FS treat as regex would work, as well as -F' | ' or -F' {1}' Jun 18, 2020 at 17:06
2

When using the gsub function to change the content of $0 (thus not substituting a particular field) the output will not get reformated:

df -h | awk '$5 ~ /[8-9][0-9]|100/ {gsub($5,"\033[1;31m"$5"\033[0m")}1'

This only works if $5 occurs only once in the line with is supposedly the case in the given example.

-1

GNU awk has an extension to split(): it will store all the fields in one array, and all the actual field separators (that matched the RE used) in another array. So you can fix value[5] to include the colouring, and then reconstitute the output line in a loop, interleaving the fields and actual separators.

https://www.gnu.org/software/gawk/manual/gawk.html#String-Functions and scroll down to split()

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .