1

I have this perfectly working command:

netstat -tuplean | awk '{NR>1; if( $6 ~ /ESTABLISHED/ ) print "\033[0;31m" $5  "   \033[01;31m"$6;if ($6 ~ /_WAIT/ ) print "\033[0;34m"$5  "   \033[01;32m"$6}'

I cannot wrap it into a watch command. Here is what I tried:

  1. escape all single quotes (')

    watch 'netstat -tuplean | awk '\''{NR>1; if( $6 ~ /ESTABLISHED/ ) print "\033[0;31m" $5  "   \033[01;31m"$6
      if ($6 ~ /_WAIT/ ) print "\033[0;34m"$5  "   \033[01;32m"$6}'\'''
    
    

    output:

    ^[0;31m34.210.39.83:443   ^[01;31mESTABLISHED
    ^[0;31m34.107.221.82:80   ^[01;31mESTABLISHED
    ^[0;31m34.107.221.82:80   ^[01;31mESTABLISHED
    ^[0;34m34.117.59.81:80   ^[01;32mTIME_WAIT
    ^[0;34m34.117.59.81:80   ^[01;32mTIME_WAIT
    ^[0;31m192.168.0.1:67   ^[01;31mESTABLISHED
    
  2. escape both single and double quotes (' and ")

    watch 'netstat -tuplean | awk '\''{NR>1; if( $6 ~ /ESTABLISHED/ ) print '\'"\033[0;31m'\'" $5  "   \033[01;31m'\'"$6
      if ($6 ~ /_WAIT/ ) print '\'"\033[0;34m'\'"$5  '\'"   \033[01;32m'\'"$6}'\'''
    

    output:

     bash: syntax error near unexpected token `print'
    
  3. export the command and then call it back this way:

     while : do ...<cmd>...; sleep 2;done
     watch -n 3 -x bash -c "$cmd" 
    

    it does not work neither because the same problem occurs when defining the variable.

  4. I tried to make a script using while : do ...<cmd>...; sleep 2;done

    it does not work because it looks like the sleep delay is not taken into account; as a result, the output comes out too fast -- there is no way to read something.

Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
achille
  • 103
  • 9

2 Answers2

4

You did not share the complete code you used in your loop-based attempts, so here are a few options you have to avoid handling multiple levels of quoting, freely based on a slightly modified AWK script.

You may save your code as an executable file:

#!/bin/bash

netstat -tuplean | awk '
  $6 ~ /ESTABLISHED/ { print "\033[0;31m" $5  "   \033[01;31m"$6 }
  $6 ~ /_WAIT/ { print "\033[0;34m"$5  "   \033[01;32m"$6 }
  $6 ~ /TIME_WAIT/ { print "\033[0;34m"$5  "   \033[01;32m"$6 }
  END { printf("%s","\033(B\033[m") }      # Turn fancy formatting off'

and make watch run it, noting that, as pointed out in the answer you already have, you also need the --color option:

watch -n 3 --color ./my_script

Alternatively, you may use an infinite loop — I am unable to guess why, in your case, "the sleep delay is not taken into account"; this seems to work as expected:

while :
do
  clear
  netstat -tuplean | awk '
    $6 ~ /ESTABLISHED/ { print "\033[0;31m" $5  "   \033[01;31m"$6 }
    $6 ~ /_WAIT/ { print "\033[0;34m"$5  "   \033[01;32m"$6 }
    $6 ~ /TIME_WAIT/ { print "\033[0;34m"$5  "   \033[01;32m"$6 }
    END { printf("%s","\033(B\033[m") }     # Turn fancy formatting off'
  sleep 3
done

To save your script in a variable and run it as bash -c "$cmd", you may combine command substitution and a here-document. If the label of a here-document is quoted (here, 'EOT'), its content is not expanded:

cmd=$(cat <<'EOT'
netstat -tuplean | awk '
  $6 ~ /ESTABLISHED/ { print "\033[0;31m" $5  "   \033[01;31m"$6 }
  $6 ~ /_WAIT/ { print "\033[0;34m"$5  "   \033[01;32m"$6 }
  $6 ~ /TIME_WAIT/ { print "\033[0;34m"$5  "   \033[01;32m"$6 }
  END { printf("%s","\033(B\033[m") }      # Turn fancy formatting off'
EOT
)
fra-san
  • 9,931
  • 2
  • 21
  • 42
  • 2
    +1. writing this as a stand-alone script is a good way to avoid quoting issues due to the conflicting quoting requirements of `watch` and shell and the `awk` script. – cas Aug 13 '21 at 14:18
  • What is `\033(B` escape code for? I've asked here [What is the meaning of ESC ( B ANSI escape code?](https://unix.stackexchange.com/q/722244/1806) – jcubic Oct 24 '22 at 16:21
  • @jcubic Honestly, I wouldn't know. Most likely I took that sequence from the output of `tput`, using a terminal emulator where `TERM` was set to `xterm`, without much thought on the meaning of every single character. – fra-san Oct 24 '22 at 18:00
3

The command where you enclosed everything in single-quotes and properly escaped the old single-quotes is almost good. It prints "garbage" because you didn't use watch --color. Run this:

watch --color 'netstat -tuplean | awk '\''{NR>1; if( $6 ~ /ESTABLISHED/ ) print "\033[0;31m" $5  "   \033[01;31m"$6
  if ($6 ~ /_WAIT/ ) print "\033[0;34m"$5  "   \033[01;32m"$6
  if ($6 ~ /TIME_WAIT/ ) print "\033[0;34m"$5  "   \033[01;32m"$6}'\'

(Note the final '' in your original code is a single-quoted empty string concatenated with what's before. It changes nothing. My code omitted this useless '' completely.)

From man 1 watch:

-c, --color
Interpret ANSI color and style sequences.

Kamil Maciorowski
  • 19,242
  • 1
  • 50
  • 94
  • .@Kamil: good point to you. Regarding the final ( ' ' ), I try to keep the logic: ( ' \ ' ' ) corresponding to the end of awk snippet and one last ( ' ) corresponding to close the watch command. – achille Aug 13 '21 at 15:17