0

I am trying to write a script (for dash, so I want it posix compliant). What I want the script to do is print me the name of my currently connected SSID (in json format).

This info is to be processed by my status bar (polybar, waybar and i3status). I would like to print this information as few times as possible, and immediately on network change.

I have found the command ip monitor useful; since it prints lines when there is a network change. However, it is very verbose. (I have similar scripts set up, and for pulseaudio, I use grep to filter unwanted lines for example) I do not neccessarily want to filter the lines; since filtering doesn't really reduce the number of lines my script prints.

I managed to write a script in bash, but the redirection is not POSIX compliant, so I can't switch to dash.

This is the code I currently have, that depends on bash's redirection

#!/bin/bash

_int="wifi"

get_text () {
    _ssid="$(iwctl station "${_int}" get-networks | awk '/>/ {print $2} ' 2>/dev/null)"
    if [ -z "${_ssid}" ] ; then
        echo '{ "format": "", "mute": true, "prefix": ""}'
    else
        echo "{ \"format\":\"${_ssid}\", \"mute\": false, \"prefix\":\" \" }"
    fi
}

while : ; do
    get_text
    _time="$(date +%s)"
    while read line; do
        if [ "$_time" != "$(date +%s)" ] ; then
            break
        fi
    done < <(ip monitor)
done

If I do this, it is POSIX compliant, but the output is printed ~20 times (the number is not consistent)

#!/bin/dash

_int="wifi"

get_text () {
    _ssid="$(iwctl station "${_int}" get-networks | awk '/>/ {print $2} ' 2>/dev/null)"
    if [ -z "${_ssid}" ] ; then
        echo '{ "format": "", "mute": true, "prefix": ""}'
    else
        echo "{ \"format\":\"${_ssid}\", \"mute\": false, \"prefix\":\" \" }"
    fi
}

ip monitor | while read line; do
    if echo $line | grep -q 'wifi' ; then
        get_text
    fi

done

EDIT: I found a solution, as I was typing my question. My loop is now the following; which checks if the time of the outputs were in different seconds.

get_text
ip monitor | while read line; do
    if echo $line | grep -q "${_int}" && [ "$_time" != "$(date +%s)" ]; then
        get_text
        _time="$(date +%s)"
    fi
done

Do note that ip monitor does print output that does not indicate network connection change. But I can handle couple prints every minute. I am afraid of very closed interspaced outputs; since those cause the infobars to be redrawn. I also have a python script that parses the arguments, so many outputs in a short time multiplies my overhead.

Michel
  • 769
  • 4
  • 19
  • If you're happy with `while read line; do ...; done < <(ip monitor)`, why not just write it as `ip monitor | while read line; do ...; done` without changing the body of the loop? – jhnc Jul 30 '19 at 22:49
  • Cause that is bash unique syntax, and is not POSIX. It won't work in dash or sh. – Batuhan Başerdem Jul 31 '19 at 14:20
  • Really? `ip monitor | while read line; do ...; done` is not POSIX? – jhnc Aug 01 '19 at 20:46
  • It is posix, but `ip monitor` still runs when the while loop breaks. So the nested loop would call many iterations of ip monitor. Bash syntax of `while read line; do ...; done < <(ip monitor)` kills the process when the while loop exits. – Batuhan Başerdem Aug 01 '19 at 21:07
  • Really?`ip monitor` seems to exit if it receives SIGPIPE – jhnc Aug 01 '19 at 21:20

0 Answers0