[gelöst] Bash - 2 Bedingungen erfüllen, dann...

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
dasebastian
Beiträge: 1886
Registriert: 12.07.2020 11:21:17

[gelöst] Bash - 2 Bedingungen erfüllen, dann...

Beitrag von dasebastian » 23.03.2024 21:10:44

Ich habe hier mittlerweile unzählige Versionen herumliegen und Knoten im Hirn. Die Aufgabenstellung dürfte klar sein:

Du checkst bitte alle 60 Sekunden, ob der Akku geladen wird und ob er über 98% (nur zu Testzwecken) geladen ist. Wenn BEIDES nicht erfüllt wird, dann benachrichtige mich.

Oder anders: Benachrichtige mich, wenn der Stand unter 98% fällt UND nicht geladen wird.

Das sollte doch eine ganz banale Aufgabe sein. Da ich aber null Scriptingkenntnisse habe, quäle ich mich so durch:

Code: Alles auswählen

#!/bin/bash

while true
do
  akkustatus=`acpi -b | grep -P -o 'Discharging'`
  akkulevel=`acpi -b | grep -P -o '[0-9]+(?=%)'`
    if [[ $akkustatus="Discharging" && $akkulevel -le 98 ]]; then
      notify-send --urgency=CRITICAL -i /usr/share/icons/simply-white-circles/scalable/panel/battery-caution-charging.svg "Gib mir Power für mein Akku!" "Nur ${akkulevel}%, ich will mehr Strom!"
 fi
 sleep 60
done
Der momentane Stand: auf $akkulevel wird eingegangen (keine Benachrichtigung wenn höher), auf $akkustatus aber NICHT. Es wird also auch benachrichtigt, wenn das Level zwar unter 98% liegt aber schon geladen wird.

Wo liege ich hier daneben? 8O
Zuletzt geändert von dasebastian am 23.03.2024 22:27:37, insgesamt 1-mal geändert.

Benutzeravatar
heisenberg
Beiträge: 3567
Registriert: 04.06.2015 01:17:27
Lizenz eigener Beiträge: MIT Lizenz

Re: Bash - 2 Bedingungen erfüllen, dann...

Beitrag von heisenberg » 23.03.2024 21:16:16

Setz' doch Mal set -x in die 2. Zeile Deines Scriptes und führe es dann aus.
Jede Rohheit hat ihren Ursprung in einer Schwäche.

juribel
Beiträge: 188
Registriert: 20.06.2023 10:17:01

Re: Bash - 2 Bedingungen erfüllen, dann...

Beitrag von juribel » 23.03.2024 21:20:42

Nach meinen bescheidenen bash-Kenntnissen ist der erste Vergleich mit "$akkustatus="Discharging"" falsch. Das Gleichheitszeichen macht doch eine Zuweisung und keinen Vergleich. Den zweiten Vergleich hast du mit "-le" durchgeführt, und der erste müsste dann bestimmt mit "-eq" durchgeführt werden.

dasebastian
Beiträge: 1886
Registriert: 12.07.2020 11:21:17

Re: Bash - 2 Bedingungen erfüllen, dann...

Beitrag von dasebastian » 23.03.2024 21:24:44

Code: Alles auswählen

$  # Alle Bedingungen werden erfüllt:
$ bash dwn/akkualarm
+ true
++ acpi -b
++ grep -P -o Discharging
+ akkustatus=Discharging
++ acpi -b
++ grep -P -o '[0-9]+(?=%)'
+ akkulevel=97
+ [[ -n Discharging=Discharging ]]
+ [[ 97 -le 98 ]]
+ notify-send --urgency=CRITICAL -i /usr/share/icons/simply-white-circles/scalable/panel/battery-caution-charging.svg 'Gib mir Power für mein Akku!' 'Nur 97%, ich will mehr Strom!'
+ sleep 60
^C
$  # Level <98 aber es wird geladen:
$ bash dwn/akkualarm
+ true
++ acpi -b
++ grep -P -o Discharging
+ akkustatus=
++ acpi -b
++ grep -P -o '[0-9]+(?=%)'
+ akkulevel=96
+ [[ -n =Discharging ]]
+ [[ 96 -le 98 ]]
+ notify-send --urgency=CRITICAL -i /usr/share/icons/simply-white-circles/scalable/panel/battery-caution-charging.svg 'Gib mir Power für mein Akku!' 'Nur 96%, ich will mehr Strom!'
+ sleep 60
^C
~ >
$ 

Benutzeravatar
heisenberg
Beiträge: 3567
Registriert: 04.06.2015 01:17:27
Lizenz eigener Beiträge: MIT Lizenz

Re: Bash - 2 Bedingungen erfüllen, dann...

Beitrag von heisenberg » 23.03.2024 21:26:46

juribel hat geschrieben: ↑ zum Beitrag ↑
23.03.2024 21:20:42
Nach meinen bescheidenen bash-Kenntnissen ist der erste Vergleich mit "$akkustatus="Discharging"" falsch. Das Gleichheitszeichen macht doch eine Zuweisung und keinen Vergleich.
In vielen Programmiersprachen hättest Du wohl Recht. In der Bash passt das aber. Hier geht beides = und ==. Aus Gründen der Verständlichkeit würde ich aber trotzdem auch in Bash immer mit == arbeiten.
Den zweiten Vergleich hast du mit "-le" durchgeführt, und der erste müsste dann bestimmt mit "-eq" durchgeführt werden.
-le / -eq / ... sind für numerische Vergleiche.
Zuletzt geändert von heisenberg am 23.03.2024 21:35:45, insgesamt 2-mal geändert.
Jede Rohheit hat ihren Ursprung in einer Schwäche.

juribel
Beiträge: 188
Registriert: 20.06.2023 10:17:01

Re: Bash - 2 Bedingungen erfüllen, dann...

Beitrag von juribel » 23.03.2024 21:29:15

Danke! Wieder was dazu gelernt :-)

dasebastian
Beiträge: 1886
Registriert: 12.07.2020 11:21:17

Re: Bash - 2 Bedingungen erfüllen, dann...

Beitrag von dasebastian » 23.03.2024 21:29:28

Nein, ich seh ihn nicht... :lol:

Benutzeravatar
heisenberg
Beiträge: 3567
Registriert: 04.06.2015 01:17:27
Lizenz eigener Beiträge: MIT Lizenz

Re: Bash - 2 Bedingungen erfüllen, dann...

Beitrag von heisenberg » 23.03.2024 21:30:44

Code: Alles auswählen

+ [[ -n Discharging=Discharging ]]
Wo kommt das -n denn her? Das darf gemäß Deines Codes da nicht stehen. Ist das wirklich exakt das gleiche Script, dass Du oben geschrieben hast und unten ausgeführt hast?

Die Bedingung [[ -n "$varname" ]] ergibt immer true, wenn varname einen Wert enthält. -> Nicht was Du willst.
Zuletzt geändert von heisenberg am 23.03.2024 21:37:20, insgesamt 1-mal geändert.
Jede Rohheit hat ihren Ursprung in einer Schwäche.

dasebastian
Beiträge: 1886
Registriert: 12.07.2020 11:21:17

Re: Bash - 2 Bedingungen erfüllen, dann...

Beitrag von dasebastian » 23.03.2024 21:36:38

heisenberg hat geschrieben: ↑ zum Beitrag ↑
23.03.2024 21:30:44
Ist das wirklich exakt das gleiche Script, dass Du oben geschrieben hast und unten ausgeführt hast.
Absolut. Nochmal ganz zur Sicherheit:

Code: Alles auswählen

#!/bin/bash
set -x
while true
do
  akkustatus=`acpi -b | grep -P -o 'Discharging'`
  akkulevel=`acpi -b | grep -P -o '[0-9]+(?=%)'`
    if [[ $akkustatus="Discharging" && $akkulevel -le 98 ]]; then
      notify-send --urgency=CRITICAL -i /usr/share/icons/simply-white-circles/scalable/panel/battery-caution-charging.svg "Gib mir Power für mein Akku!" "Nur ${akkulevel}%, ich will mehr Strom!"
 fi
 sleep 60
done
Zuerst alles erfüllt, dann Strom an:

Code: Alles auswählen

$ bash dwn/akkualarm
+ true
++ acpi -b
++ grep -P -o Discharging
+ akkustatus=Discharging
++ acpi -b
++ grep -P -o '[0-9]+(?=%)'
+ akkulevel=94
+ [[ -n Discharging=Discharging ]]
+ [[ 94 -le 98 ]]
+ notify-send --urgency=CRITICAL -i /usr/share/icons/simply-white-circles/scalable/panel/battery-caution-charging.svg 'Gib mir Power für mein Akku!' 'Nur 94%, ich will mehr Strom!'
+ sleep 60
^C
$ bash dwn/akkualarm
+ true
++ acpi -b
++ grep -P -o Discharging
+ akkustatus=
++ acpi -b
++ grep -P -o '[0-9]+(?=%)'
+ akkulevel=94
+ [[ -n =Discharging ]]
+ [[ 94 -le 98 ]]
+ notify-send --urgency=CRITICAL -i /usr/share/icons/simply-white-circles/scalable/panel/battery-caution-charging.svg 'Gib mir Power für mein Akku!' 'Nur 94%, ich will mehr Strom!'
+ sleep 60
^C
$ 

Benutzeravatar
heisenberg
Beiträge: 3567
Registriert: 04.06.2015 01:17:27
Lizenz eigener Beiträge: MIT Lizenz

Re: Bash - 2 Bedingungen erfüllen, dann...

Beitrag von heisenberg » 23.03.2024 21:39:02

Kannst Du mal die Ausgabe von acpi -b für beide Modi zeigen (Laden + Nicht mit dem Stromnetz verbunden)?
Jede Rohheit hat ihren Ursprung in einer Schwäche.

dasebastian
Beiträge: 1886
Registriert: 12.07.2020 11:21:17

Re: Bash - 2 Bedingungen erfüllen, dann...

Beitrag von dasebastian » 23.03.2024 22:05:22

Code: Alles auswählen

~ >
$ # wird geladen
~ >
$ acpi -b
Battery 0: Charging, 95%, 00:11:25 until charged
~ >
$ # wird entladen
~ >
$ acpi -b
Battery 0: Discharging, 95%, 03:04:51 remaining
~ >
$ 

Benutzeravatar
heisenberg
Beiträge: 3567
Registriert: 04.06.2015 01:17:27
Lizenz eigener Beiträge: MIT Lizenz

Re: Bash - 2 Bedingungen erfüllen, dann...

Beitrag von heisenberg » 23.03.2024 22:10:37

Das Problem ist wohl das ...

Code: Alles auswählen

if [[ $akkustatus="Discharging" ...
a) Du verwendest keine Leerzeichen um die einzelnen Elemente zu trennen.
b) Du verwendest kein Quoting.

Bei mir sieht Dein Befehl nach Auflösung durch "set -x" anders aus (vermutlich andere Bash Version), bewirkt aber das Gleiche.

Variante 1:

Code: Alles auswählen

t=""
set -x
if [ "$t" = "hallo" ]; then echo $t; echo "ist gleich hallo";fi
+ '[' '' = hallo ']'
Das wird korrekt so interpretiert, wie gewünscht: Der Vergleich schlägt fehl.

Variante 2:

Code: Alles auswählen

t=""
set -x
if [ $t="hallo" ]; then echo ">$t< ist gleich hallo";fi
+ '[' =hallo ']'
+ echo '>< ist gleich hallo'
Die Bash erkennt hier keinen Operator, sondern nur ein Literal (Zeichenkette) und wendet per Default da -n darauf an, was immer zutrifft, weil da ja eine nicht-leere Zeichenkette steht.

Das war mir so auch noch nicht bewusst ...

Wenn man nur die Elemente durch ein Leerzeichen getrennt hätte - also kein Quoting - bekäme man einen Syntaxfehler:

Code: Alles auswählen

if [ $t = "hallo" ]; then echo $t; echo "ist gleich hallo";fi
+ '[' = hallo ']'
-bash: [: =: Einstelliger (unärer) Operator erwartet.
Jede Rohheit hat ihren Ursprung in einer Schwäche.

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: Bash - 2 Bedingungen erfüllen, dann...

Beitrag von JTH » 23.03.2024 22:25:02

heisenberg hat geschrieben: ↑ zum Beitrag ↑
23.03.2024 22:10:37
Das Problem ist das ...

Code: Alles auswählen

if [[ $akkustatus="Discharging" ...
b) Du verwendest kein Quoting.
In der Bash (gilt nicht für Posix-Shell) muss man die Operanden von == und != innerhalb von [[ … ]] (gilt nicht für [ … ]) nicht quoten. In [[ … ]] findet nämlich kein Wordsplitting statt. Man muss nur den rechten Operand quoten, wenn man den nicht als Pattern, sondern als Literal interpretiert haben möchte. Das ist hier daher nicht Mitursache des Problems ( a) ist völlig richtig und zutreffend).

Da das eher ein Detailwissen ist, sollte man es schnell wieder vergessen und Variablen immer, immer quoten, wo sie verwendet werden:

Code: Alles auswählen

"$var"
Es gibt nur sehr wenige Stellen, in denen man Quoting bewusst nicht haben möchte, es kann aber viele Probleme und ungewolltes Verhalten verhindern.
Manchmal bekannt als Just (another) Terminal Hacker.

dasebastian
Beiträge: 1886
Registriert: 12.07.2020 11:21:17

Re: Bash - 2 Bedingungen erfüllen, dann...

Beitrag von dasebastian » 23.03.2024 22:26:37

HA!

Code: Alles auswählen

#!/bin/bash
set -x

while true
do
  akkustatus=`acpi -b | grep -P -o 'Discharging'`
  akkulevel=`acpi -b | grep -P -o '[0-9]+(?=%)'`
    if [[ "$akkustatus" = "Discharging" && $akkulevel -le 98 ]]; then
      notify-send --urgency=CRITICAL -i /usr/share/icons/simply-white-circles/scalable/panel/battery-caution-charging.svg "Gib mir Power für mein Akku!" "Nur ${akkulevel}%, ich will mehr Strom!"
 fi
 sleep 60
done

Code: Alles auswählen

$  # Entladung
~ >
$ bash dwn/akkualarm2
+ true
++ acpi -b
++ grep -P -o Discharging
+ akkustatus=Discharging
++ acpi -b
++ grep -P -o '[0-9]+(?=%)'
+ akkulevel=87
+ [[ Discharging = \D\i\s\c\h\a\r\g\i\n\g ]]
+ [[ 87 -le 98 ]]
+ notify-send --urgency=CRITICAL -i /usr/share/icons/simply-white-circles/scalable/panel/battery-caution-charging.svg 'Gib mir Power für mein Akku!' 'Nur 87%, ich will mehr Strom!'
+ sleep 60
^C
~ >
$  # Ladung
~ >
$ bash dwn/akkualarm2
+ true
++ acpi -b
++ grep -P -o Discharging
+ akkustatus=
++ acpi -b
++ grep -P -o '[0-9]+(?=%)'
+ akkulevel=87
+ [[ '' = \D\i\s\c\h\a\r\g\i\n\g ]]
+ sleep 60
^C
~ >
$ 
Verhalten wie gewünscht, das macht Freude, danke dir! :THX:

dasebastian
Beiträge: 1886
Registriert: 12.07.2020 11:21:17

Re: Bash - 2 Bedingungen erfüllen, dann...

Beitrag von dasebastian » 23.03.2024 22:45:38

JTH hat geschrieben: ↑ zum Beitrag ↑
23.03.2024 22:25:02
In der Bash (gilt nicht für Posix-Shell) muss man die Operanden von == und != innerhalb von [[ … ]] (gilt nicht für [ … ]) nicht ...
8O
... In [[ … ]] findet nämlich kein Wordsplitting statt. Man muss nur den rechten Operand quoten, wenn man den nicht als Pattern, sondern als Literal interpretiert haben möchte...
8O 8O
Da das eher ein Detailwissen ist, sollte man es schnell wieder vergessen und Variablen immer, immer quoten...
Aaaah, guttt! :lol:

Danke euch! :THX:

Benutzeravatar
heisenberg
Beiträge: 3567
Registriert: 04.06.2015 01:17:27
Lizenz eigener Beiträge: MIT Lizenz

Re: [gelöst] Bash - 2 Bedingungen erfüllen, dann...

Beitrag von heisenberg » 23.03.2024 22:52:33

...und wenn ein normaler 'grep -F' (FIXED/FAST) reicht, dann würde ich auf jeden Fall dem den Vorzug gegenüber 'grep -P' (PCRE) geben, bzw. mich mit dem normalen grep begnügen. 'grep -P' habe ich in einigen Jahrzehnten jetzt bestimmt nur sehr wenige Male wirklich gebraucht.

Desweiteren verzichte ich grundsätzlich auf Kommandosubstitution via `...`. Ich verwende immer $( ... ). Das ist viel klarer, da es die starke optische Ähnlichkeit von ` und ' und " vermeidet und so die Lesbarkeit des Codes erhöht. Ebenso erlaubt es sehr leicht mehrere Subshells ohne sich mit dem Quoting da verrenken zu müssen.
In der Bash (gilt nicht für Posix-Shell) muss man die Operanden von == und != innerhalb von [[ … ]] (gilt nicht für [ … ]) nicht quoten.
Und mir ist das nicht aufgefallen, weil ich direkt mit [ ... ] statt mit [[ ... ]] getestet habe.
Jede Rohheit hat ihren Ursprung in einer Schwäche.

Antworten