bash для цикла не делает цикл таким, как задумано

#bash #for-loop

Вопрос:

Я взял этот скрипт где-то в Интернете, который автоматически переключается на лучшую сеть Wi-Fi. Еще несколько недель назад все работало нормально. Я немного изменил его, чтобы попытаться выяснить, в чем проблема, и, похоже, цикл for неправильно повторяется в списке доступных сетей Wi-Fi. Любые идеи будут оценены по достоинству. Вот сценарий:

 #!/bin/bash
threshold=10

# Lets do a scan first
sudo /usr/bin/nmcli -t -f ssid,signal,rate,in-use dev wifi rescan

# And get the list of known networks
known_networks_info=$(/usr/bin/nmcli -t -f name connection show | sed -e 's/^Auto //g')
echo "knowm networks"
echo $known_networks_info

# What's the current network, yet?
current_network_name=$(/usr/bin/nmcli -t -f ssid,signal,rate,in-use dev wifi list | grep ':*' | cut -d ':' -f1)
current_network_strength=$(/usr/bin/nmcli -t -f ssid,signal,rate,in-use dev wifi list | grep ':*' | cut -d ':' -f2)
echo "current net $current_network_name, strength $current_network_strength"

# Now see if we have a better network to switch to. Networks are sorted by signal strength so there's no need to check them all if the first signal's strength is not higher than current network's strength   threshold.
network_list=$(/usr/bin/nmcli -t -f ssid,signal,rate,in-use dev wifi list | grep -v $current_network_name | sort -nr -k2 -t':')
echo "network list"
echo $network_list
typeset -p network_list
for network in "$network_list" ; do
        network_name=$(echo $network | cut -d ':' -f1)
        network_strength=$(echo $network | cut -d ':' -f2)
        echo "net $network_name, strength $network_strength"
        # if [[ "$network_name" == "" ]]; then continue ; fi # MESH hotspots may appear with an non existent SSID so we skip them 
        # if [[ "$known_networks_info" == *"$network_name"* ]]; then
        #         if [ $network_strength -ge $(($current_network_strength   $threshold)) ]; then
        #                 notification="Switching to network $network_name that has a better signal ($network_strength>$(($current_network_strength   $threshold)))"
        #                 echo $notification
        #                 notify-send "$notification"
        #                 sudo /usr/bin/nmcli device wifi connect $network_name
        #         else
        #                 notification="Network $network_name is well known but its signal's strength is not worth switching"
        #                 echo $notification
        #                 notify-send "$notification"
        #                 exit 0
        #         fi
        # fi
done
 

Это результат приведенного выше сценария:

 knowm networks
Amara Amara_EXT Kira Kira_5g Kira_5G Kira_5GEXT Kira_EXT RedmiGao RedmiKira VTR-2201458 VTR-2201458_EXT VTR-2201458_EXT2 VTR-9329907 VTR-9329907_EXT Wired connection 1
current net Amara, strength 82
network list
HUAWEI-B2368-472705:80:270 Mbit/s: HUAWEI-B2368-5G-472706:70:270 Mbit/s: Mi 10T Pro:62:130 Mbit/s: Irene.:50:130 Mbit/s: C L E Y A 5G:32:540 Mbit/s: C L E Y A:32:540 Mbit/s: Irene.:25:540 Mbit/s: Irene. 5G:22:540 Mbit/s: Mateo:15:130 Mbit/s:
declare -- network_list="HUAWEI-B2368-472705:80:270 Mbit/s: 
HUAWEI-B2368-5G-472706:70:270 Mbit/s: 
Mi 10T Pro:62:130 Mbit/s: 
Irene.:50:130 Mbit/s: 
C L E Y A 5G:32:540 Mbit/s: 
C L E Y A:32:540 Mbit/s: 
Irene.:25:540 Mbit/s: 
Irene. 5G:22:540 Mbit/s: 
Mateo:15:130 Mbit/s: "
net HUAWEI-B2368-472705, strength 80
 

Комментарии:

1. основной проблемой является for цикл разбивается $network_list на пробелы, но не могу сказать из этого примера, если это связано с вашими изменен вывод в nmcli выходной или пропавших двойных кавычек в первую for петлю; соедините предложения: добавить typeset -p network_list перед основным for петлю (так мы сможем увидеть, что на самом деле в $network_list ; попробуйте добавить двойные кавычки в первом for цикле, например, for network in "$network_list" (это должно

2. @markp-fuso спасибо за ваши комментарии. Я обновил вопрос в соответствии с вашим первым вопросом, добавил соответствующий вывод. Я пытаюсь понять, как сделать ваш второй комментарий.

3. проигнорируйте мой 2-й комментарий (теперь удален) … Я забегал вперед; подумайте о замене внешнего for контура на while read -r network; do ... ; done <<< "${network_list}"

4. @markp-fuso спасибо, что сработало, я опубликую ответ с вашим решением

5. На самом деле, я бы рекомендовал использовать while IFS=: read -r network_name network_strength network_speed; do ... и пропустить использование cut для извлечения этих полей.

Ответ №1:

Спасибо @markp-fuso и @GordonDavisson за комментарии, вот исправленный скрипт:

 #!/bin/bash
threshold=10

# Lets do a scan first
sudo /usr/bin/nmcli -t -f ssid,signal,in-use dev wifi rescan

# And get the list of known networks
known_networks_info=$(/usr/bin/nmcli -t -f name connection show | sed -e 's/^Auto //g')
echo "knowm networks"
echo $known_networks_info

# What's the current network?
current_network_name=$(/usr/bin/nmcli -t -f ssid,signal,rate,in-use dev wifi list | grep ':*' | cut -d ':' -f1)
current_network_strength=$(/usr/bin/nmcli -t -f ssid,signal,rate,in-use dev wifi list | grep ':*' | cut -d ':' -f2)
echo "current net $current_network_name, strength $current_network_strength"

# Now see if we have a better network to switch to. Networks are sorted by signal strength so there's no need to check them all if the first signal's strength is not higher than current network's strength   threshold.
network_list=$(/usr/bin/nmcli -t -f ssid,signal,rate,in-use dev wifi list | grep -wv $current_network_name | sort -nr -k2 -t':')
echo "network list"
echo $network_list
echo "checking each network"
while IFS=: read -r network_name network_strength network_rate; do 
        echo "net $network_name, strength $network_strength"
        if [[ "$network_name" == "" ]]; then continue ; fi # MESH hotspots may appear with an non existent SSID so we skip them 
        if [[ "$known_networks_info" == *"$network_name"* ]]; then
                if [ $network_strength -ge $(($current_network_strength   $threshold)) ]; then
                        notification="Switching to network $network_name that has a better signal ($network_strength>$(($current_network_strength   $threshold)))"
                        echo $notification
                        notify-send "$notification"
                        sudo /usr/bin/nmcli device wifi connect $network_name
                else
                        notification="Network $network_name is well known but its signal's strength is not worth switching"
                        echo $notification
                        notify-send "$notification"
                fi
                exit 0
        fi
done <<< "${network_list}"