Bash Skript mit if Abfrage wirft Fehler aus?

2 Antworten

Verzichte auf das sudo im Skript und führe das Skript mit den nötigen Rechten aus. Braucht es das sudo überhaupt, wenn ja wozu?

fragwuerdiger81 
Fragesteller
 10.12.2018, 08:11

Das Skript sollte aber ansonsten so passen? Das seltsame ist ja das auch nur bei einem echo Befehl das Skript nicht sauber durchläuft.

Alle Skripte die ich bisher dafür erstellt habe funktionieren ansonsten und laufen alle auf 755.

Den sudo habe ich nur drin weil mir aufgefallen war, bei anderen Skripten, dass die im Skript gestarteten Prozesse händisch ausgeführt als User laufen. Normalerweise soll alles vollautomatisch über Cron laufen. Ich benutze dazu sudo crontab -e.

Inwieweit es für meine Zwecke einen Unterschied macht ob ich als User oder als su laufen lasse weiß ich nicht aber als Linux Amateur sorgt sudo am wenigstens für Frust. :)

0
KarlRanseierIII  10.12.2018, 15:41
@fragwuerdiger81

Erstmal vornweg, sudo verschafft Dir erweiterte Rechte - cron kann Dir das skript aber auch direkt mit erweiterten Rechten starten und dann wird halt alles in diesem Kontext ausgeführt.

Unreflektiert sudo zu verwenden ist nicht sonderlich gut/toll - das Gleiche gilt dann natürlich für das Skript mit erweiterten Rechten, man überlegt sich halt, ob diese wirklich nötig sind und wenn ja, wofür.

Du kannst ping auch mit -q starten, dann wird bis auf die Summary erst gar kein Output generiert. Sonst sieht das Skript soweit erstmal okay aus.

0
fragwuerdiger81 
Fragesteller
 10.12.2018, 20:31
@KarlRanseierIII

Danke dir erstmal für deine Antwort.

Ich habe inzwischen herausgefunden woran es lag.

Leider war mir nicht bewusst dass ich im notepad++ unter Windows das Zeilenende auf Unix stellen muss.

Nun läuft das Skript auch.

Dafür gibt es direkt das nächste Problem.

Folgendes Skript läuft um zu prüfen ob die Kamera erreichbar ist

https://pastebin.com/w4T3MSKN

und startet dann ein neues Skript welches im Falle eines Abbruchs prüft ob die Kamera wieder erreichbar ist

https://pastebin.com/9XbeQQST

ist dies der Fall startet folgendes Skript

https://pastebin.com/K2kxKEb1

welches eine ffmpeg Aufnahme startet sowie die pid von ffmpeg in eine Datei umleitet, da ich diese ffmpeg Instanz später identifizieren möchte um diese zu beenden.

Das Problem entsteht nun beim zweiten Skript da ping nicht wartet bis die Kamera wieder erreichbar ist. Da wird wohl ein Denkfehler drin sein und ich komme auch nicht durch probieren ans Ziel.

Sollte ich für das Warten auf Erreichbarkeit besser netcat statt ping nutzen?

0
KarlRanseierIII  10.12.2018, 20:47
@fragwuerdiger81

Also bevor ich das durchlese:

Ist Dir soweit klar, daß ping nicht beendet wird, unabhängig davon, ob es Antworten bekommt oder nicht?

mit -i 5 setzt Du ein 5 Sekunden Intervall, alle 5 Sekunden feuert ping also ein ICMP Echo-Req und macht das solange, bis die Zeit abgelaufen ist. Ob es in dieser Zeit Antwort bekommt oder nicht, ist ihm dabei völlig egal.

Ist das soweit vogresehen - oder ergibt das überhaupt Sinn?

Normalerweise wäre es ja sinnvoller, wenn entweder:

1.) cron alle x Minuten prüft ob errreichbar und sonst reagiert.

2.) Du durchgängig in kurzen Intervallen wie mit Ping anpingst und sobald <threshold> Antworten ausbleiben. angenommen wird, die Gegenseite ist unerreichbar.

Wie soll denn die Grundlogik von dem ganzen aussehen?

0
fragwuerdiger81 
Fragesteller
 11.12.2018, 08:44
@KarlRanseierIII

Ok danke dir erstmal!!

Also das Teil ist für den 24/7 Gebrauch konzipiert und soll möglichst vollautomatisch arbeiten. Es werden 4 IP Kameras von ffmpeg jeweils für 24h aufgezeichnet. Das Skript dazu startet per Cron jeden Tag @midnight neu. Die Dateien vom Vortag landen in einem Archiv wo sie maximal 21 Tage bleiben und per täglichen cronjob gelöscht werden. Für den Fall dass ein Reboot vom RPI stattfindet gibt es passende @reboot Skripte (max. 24h Läuferzeit) und die in dem Fall dazugehörigen ffmpeg Prozesse werden um Mitternacht anhand der PID (würden in Datei hinterlegt) gekillt und die routinemäßigen Aufnahmen starten wieder für 24h, um doppelte Aufnahmen zu vermeiden. Das läuft auch alles bestens. Was mir Probleme macht ist der Fall wenn die Verbindung (Netzwerk oder Kamera) mal ausfällt.

Ist eine Kamera off, soll möglichst direkt nachdem die wieder on ist eine Aufnahme stattfinden, dazu die drei Skripte. Ping überwacht die Erreichbarkeit und gibt im Falle eines Abbruchs weiter an Skript Nummer 2. Das klappt auch soweit. Wenn ich bei einer Kamera den Stecker ziehe wird ping beendet und Skript Nummer 2 läuft an. Nun soll gepingt werden bis die Kamera wieder antwortet und dann an Skript 3 abgegeben werden, welches die Aufnahmekommandos der jeweiligen Kamera bereit hält.

Das Problem ist nun, Skript Nummer 2 wartet nicht auf Erreichbarkeit. Es läuft an und nach ein paar Sekunden steht da die echo Ausgabe anstatt weiter zu pingen. Mir sind zu viele Ungereimtheiten was die if Sache betrifft. So wie es in Skript 1 deklariert ist, scheint es für den Zweck super zu passen aber in Skript zwei eben nicht mehr, obwohl selbes Prinzip nur umgekehrt. Dort wird halt nach meinem Verständnis auf Ausgabe 1>/dev/null gewartet bis von ping der exit code 0 (Gerät erreichbar) kommt und es wird das Skript per else ausgeführt. Stattdessen kommt nach ein paar Sekunden die then Ausgabe also der echo Befehl. Ist dieser echo Befehl eigentlich nicht überflüssig? Skript 1 läuft so zumindest. Never change a running system ^^

Wie gesagt ich suche mir bis jetzt alles mühsam zusammen und versuche mir einen Reim daraus zu machen und testen testen verstehen. :)

Gestern war schon etwas spät und die Dokumentation des Ganzen, mache ich von allen meinen umfangreicheren Bastelprojekten, nimmt auch viel Zeit in Anspruch. Ich schätze ich bin am finalen Schliff und werde wieder durch testen noch zur Lösung kommen. :)

0
KarlRanseierIII  11.12.2018, 09:04
@fragwuerdiger81

Tatsache, ping bricht tatsächlich ab, wenn Antworten ausbleiben, man lese die Doku und verinnerliche den Unterschied zwischen -w und -W ...

Ich sehe allerdings keine geeigneten Parameter, um zu pingen bis Antwort kommt und dann abzubrechen. Davon ab prüft ping ja nur, ob ein Teil des Stacks funktioniert.

Wie verhält ffmpeg sich eigentlich bei Störungen, es gibt ja noch andere Tools, wenn es nur um das Abgreifen des Streams geht.

Was Du in 2 theoretisch machen könntest, Ping mit einem fixen count starten und schauen, was der Rückgabewert ist. In der Hoffnung, daß dieser sich von (Fehler) auf normale Beendigung ändert. Das ganze als Schleife und das sollte es dann schon sein.

Aber das ist schon ziemlich hacky und wüst :-D.

0
fragwuerdiger81 
Fragesteller
 11.12.2018, 12:32
@KarlRanseierIII

^^ also bei meiner Recherche bin ich noch auf Netcat und cURL gestoßen... die könnten so etwas evtl auch erfüllen. Ich schau mir das noch mal an.

Irgendwie erwische ich mich oft dabei keine Dokus der Programme zu lesen :D... learning by doing. Und dann passiert eben das was in Nummer 2 passiert, gut dass du meine Vermutung bestätigst. Dann werde ich weiter testen und deinen hacky Tipp durchspielen oder mit nc oder curl weiter machen.

Im Prinzip ist nun ja die Idee ping freien Lauf zu lassen und eben die then Regel in ein Skript umzuleiten welches wieder ping mit den selben Parametern startet. Irgendwann wird sich die Kamera schon wieder melden ^^ und dann greift das Aufnahmeskript.

Ich würde schon gerne bei ffmpeg bleiben. Habe es extra selbst compiliert (für mich ist das viel Aufwand ^^). Zudem liegt meine CPU Last (RPI 3b+) mit 4 Streams gleichzeitig bei 0%. Da gibt es beim Bewegen des Mauszeigers über VNC mehr Ausschlag :)... sind allerdings ja auch nur copys und keine transkodierten Streams.

Ich berichte dann ;)

0
KarlRanseierIII  11.12.2018, 17:43
@fragwuerdiger81

Nur als Ergänzung, es gäbe noch rtmpdump oder auch openrtsp, diese können auch streams grabben. (mplayer geht natürlich auch)

Es gibt auch Fehlerbedingungen, bei denen die Kamera wohl via Netzwerk erreichbar ist, aber der Stream nicht länger ausgeliefert wird - da hat sich dann jemand ein Skript gebastelt, welches die Dateigrößen überwacht und wenn diese einige Zeit nicht mehr gewachsen sind, entsprechend neu startet.

Scheint der KRam ist alles, nur nicht brauchbar entwickelt :-D.

curl ist übrigens eigentlich ein http fetcher (in erster linie) inklusive C-Bibliothek für eigene Anwendungen, netcat wird gerne als das Schweizer Taschenmesser fürs Netzwerk bezeichnet - Es gibt auch verschiedene Netcats mit unterschiedlichem Funktionsumfang - direkt im Kopf hätte ich mit NC aber keinen Ansatz.

0
fragwuerdiger81 
Fragesteller
 12.12.2018, 00:55
@KarlRanseierIII

Hallo Karl :)

Also ich habe jetzt einen Ansatz mit fping probiert aber ich stolpere immer wieder über die Interpretation von if then. Ich habe wohl einfach noch nicht die richtige Kombi herausgefunden. ^^ Zumindest weiß ich jetzt was genau >/dev/null ist (sog. schwarzes Loch für Ausgaben) und was es mit stdout und stderr auf sich hat. :D

Trotzdem egal wie ich es drehe und wende, ich lande immer wieder entweder beim then echo oder in einer Schleife. Mir fehlt der letzte Kniff damit in Skript Nummer 2 fping einfach nur anfragt und bei Rückmeldung else also das nächste Skript abläuft. Anders als ping beendet sich fping nicht einfach wenn keine Erreichbarkeit gegeben ist sondern probiert munter weiter als Loop. Dementsprechend musste ich da wieder einlenken und habe hier ebenfalls eine PID für fping anlegen lassen, mit deren Hilfe in Skript 3 dann fping den Kill bekommt, da auch in dem Fall wo der Ping erfolgreich war fping weiter ausgeführt wird obwohl nicht mehr benötigt.

Aktuell sieht Skript 2 folgendermaßen aus:

https://pastebin.com/qQCi6twT

Eine Sache ist mir noch zu bash aufgefallen. Wenn in einem bash ein weiteres bash angewiesen wird, wird dann alles weitere was in dem Ursprungsbash folgt abgeschnitten und zum deklarierten Skript übergeben? Ich habe dies bemerkt während ein bash im bash gestartet werden sollte, dies auch klappte aber ein nachfolgender ffmpeg Befehl einfach missachtet wurde.

Da lege ich den bash Befehl wohl lieber ans Ende des Skripts.

Aber was wäre wenn ich mehrere Siripte aus einem Skript starten möchte? Ich finde das nämlich sehr praktisch ^^

Ist doch sehr umfangreich das ganze :)

Danke für deine Tipps, ich schaue mir das an. ;)

Was die abweichenden Paketdaten angeht... du machst mir Angst ^^... wie soll das zu Stande kommen? :)

0
KarlRanseierIII  12.12.2018, 01:50
@fragwuerdiger81

Okay, minimalistische Grundlagen des Shellscripting, Kapitel 1:

Ein Shell Script besteht aus einer Folge von Befehlen, diese werden von der Shell der Reihenfolge nach gestartet, seriell, d.h., erst wenn a fertig ist, wird b gestartet.

Rufe ich also in einem Script ein anderes auf, so wird dieses aufgerufene Script so ausgeführt, als sei es ein Befehl. D.h. der Kontrollfluß geht in das neue Skript über, sobald dieses beendet ist, kehrt er zum aufrufeneden Skript zurück und die Abarbeitung wird fortgesetzt.

Möchte ich das aktuell laufende Skript tatsächlich nich weiter ausführen, so darf ich den Prozess nicht als Kind starten, sondern muß direkt das aktuelle Skript ersetzen, hierfür wird exec verwendet.

Achtung: Kinder erben alle Grundeigenschaften der Eltern, beim Scripting insbesondere von Interesse: Die Umgebung(svariablen) und sonstige Variablen der Elternscripts, die je nach Wunsch erhalten werden können.

D.h. wenn fping sich selbst nicht beendet (oder durch was auch immer beendet wird), so kehrt der Kontrollfluß nicht in das Script zurück. Man kann natürlich auch Befehle im Hintergrund ausführen lassen.

---- snip ---- snap ----

Du mußt ein Skript übrigens nicht mit bash scriptname <parameter> aufrufen, Du darfst auch gerne ein chmod +x auf das Script machen, in der ersten Zeile ein #!/bin/bash einfügen, dann kannst Du das skript direkt starten, wie jedes andere Kommando auch, das liest sich besser ;-).

---- snap ---- snip ----

Äh, was für abweichende Paketdaten?

0
fragwuerdiger81 
Fragesteller
 12.12.2018, 23:00
@KarlRanseierIII

Inzwischen habe ich eine Lösung gefunden. Das Script funktioniert und sieht aktuell so aus

https://pastebin.com/UBX6Py8T

Ich bin wieder zurück zu ping allerdings in Kombination mit while.

Jetzt hänge ich noch am dritten Skript und verstehe nicht ganz die Unterschiede von bash, exec, source und ./

Erstmal danke für deine Erklärung. Das leuchtet mir nun ein aber wie kann ich denn am besten in Skript Nummer 3 nach oder vor dem ffmpeg Befehl ein weiteres Skript sauber und unterbrechungsfrei anweisen? 

Zu den Paketdaten... Du meintest ein User hatte ein Skript erstellt um zu überwachen ob tatsächlich Daten geschrieben werden bzw ob die Dateien wachsen. Ich frage mich bloß warum eine Kamera, obwohl sie online ist, keine Daten hergibt. :)

0
KarlRanseierIII  13.12.2018, 05:29
@fragwuerdiger81

Warum eien Kamera die eigentlich online ist keinen Stream mehr sendet, das ist eien gute Frage :-). Aber wie heißt es so schön:

Man hat schon Pferde vor der Apotheke kotzen sehen.

Okay, Sourcing verhält sich eher wie ein Include, es wird so getan als würde der Inhalt der gesourcten Datei genau an der Stelle des Sourcings ausgeführt.

Bei exec wird der Kontrollfluß übergeben und wir können nicht mehr in die aufrufende Shell zurückkehren.

Das Skript 2 sieht jetzt im Prinzip so aus, wie ich mir das dachte, in einer Schleife immer wieder Pingen, bis die CAM wieder antwortet. BEdenke aber, daß die Schleife nur terminiert, wenn die Kamera wieder hochkommt, eventuell möchtest Du die Anzahl der Durchläufe beschränken, das ist aber Feinarbeit.

----

#!/bin/bash

do work ...
if condition; then
   exec Something
else
   echo "False"
fi
echo "Hier kommen wir nie hin, wenn Bedingung wahr wird."

----

Snippet 1 <Datei host.sh>:

HOST="192.168.1.1"

Script:

#!/bin/bash

echo "Host: ${HOST}" # Variable ist leer ...
source host.sh #Sourcing, alternative Schreibweise . /host.sh
echo "Host: ${HOST}" # Variable enthält nun den Host und es wird 192.168.1.1 ausgegeben.

Das Einbinden von einfachen Skripten, die Parameter festlegen ist eines der typischen Anwendungsfelder des Sourcings, macht jedes klassische Initsystem so, oder z.B. Skripte, die nur Funktionen enthalten.

Im Prinzip kannst Du das auch alles in der manpage von bash nachlesen, dort wird das erklärt, zum Beispiel:

      exec [-cl] [-a name] [command [arguments]]

             If command is specified, it replaces the shell. No new process is created. The arguments become the arguments to command.......

Es folgt noch deutlich mehr Text.

0
fragwuerdiger81 
Fragesteller
 14.12.2018, 10:08
@KarlRanseierIII

Ok das muss erstmal sacken :)

Ich bin mir noch nicht ganz sicher was der Vorteil bzw Nachteil von exec und.source ist aber ich vermute für meinen Fall tuts exec ganz gut :) zumindest wenn direkt an ein neues Script übergeben werden soll /kann und keine weiteren Befehle folgen. Source bzw. / benutze ich dann für den Fall wenn ich ein Script weiter laufen lassen möchte. Also dann erst. /Script.sh danach ffmpeg oder wäre das sogar egal?

Also das Script 2 nur bei Erreichbarkeit auslöst passt schon , da das Teil ja für den 24/7 Einsatz konzipiert ist. Oder schwebt dir da eine mögliche Fehlerquelle vor?

0
KarlRanseierIII  14.12.2018, 11:44
@fragwuerdiger81

Wie gesagt, stelle dir Sourcing so vor, als würde das gesourcte script lokal eingeklebt werden. Der Unterschied ist vor allem, daß keine neuer Subprozess erstellt wird. Der Rückgabewert beim Sourcing ist der des letzen Kommandos. (Siehe ausführlicher in der Manpage).

Exec überlagert, ich mache nochmal ein anderes Beispiel:

#!/bin/bash

echo "Exec-ing!"
exec ping -c 10 192.168.0.1
echo "Irgendwas" <- Hier kommen wir nie hin

exec ersetzt den Shell Prozess, der neue Prozess übernimmt dabei die PID. D.h. danna auch wenn Ping beendet wird, beendet sich nicht das Shell skript, denn dei Shell existiert schon nicht mehr, der Elternprozess ist dann der, der die shell gestartet hatte.

Für die volle Tragweite des Unterschiedes muß man vermutlich verstehen, wie das mit den Prozessen insgesamt abläuft.

Für Dich ist erstmal nur wichtig: exec ersetzt das aktuelle Laufende komplett und das war es.

0
fragwuerdiger81 
Fragesteller
 18.12.2018, 23:46
@KarlRanseierIII

So... ich hatte mal wieder etwas Zeit zum testen. Alle Skripte sind soweit ok und laufen sauber durch. Ich habe auch noch postfix aufgesetzt und bekomme nun eine Mail wenn der RPI einen Reboot hinter sich hatte oder falls eine Kamera Verbindungsabbrüche erfuhr. Soweit also wie ich es mir vorgestellt habe.

Eine Sache wäre da aber noch. Der Scriptablauf ist ja so aufgebaut >
ausgehend von einem Reboot
1. ping so lange bis Kamera nicht erreichbar

https://pastebin.com/q383JFHB

-> dann

2. ping so lange bis Kamera wieder erreichbar
https://pastebin.com/k7zkeX4U

-> dann

3. sende Mail, bereinige den letzten ffmpeg Prozess falls vorhanden, führe das ffmpeg capture aus und -> starte Nr.1 erneut
https://pastebin.com/0NdU6nq9

Das ist ja eine Dauerschleife mir ist aufgefallen, dass das Script trotzdem weiterläuft auch wenn ich ping aus Nr. 1 abschiesse. Das ist dann quasi wie ein "Kamera ist nicht erreichbar" und das Script spult lustig ab. Somit habe ich dann durch jeden Kill eine neue ffmpeg Instanz, ob Daten kommen oder nicht und das ganze geht von vorne los. Ich möchte ping aber gerne kurz bevor die täglichen Routinescripte starten abschiessen, damit nicht hinterher 2 ping Prozesse die Kamera prüfen und wenn die Falle zuschnappt dementsprechend 2 Streams aufgezeichnet werden.

Ich hoffe das war jetzt irgendwie halbwegs gut erklärt :)

Die Lösung könnte ja sein die dem Script zugehörige Bash abzuschiessen. Jetzt müsste ich halt noch rausfinden wie ich die Bash PID in eine Datei bekomme... durch cron direkt evtl... oder gibt es einen Denkfehler im Scriptablauf ?

0
KarlRanseierIII  19.12.2018, 00:25
@fragwuerdiger81

Nein, das passt soweit, denke ich.

Du kannst übrigens in dem Script mit dem Dauerping TRAPs nutzen, um es über Signale zu steuern :-D.

Die PID der aktuellen Shell bekommst Du mit $$, schreib die In eine Datei und Du kannst die bash als übergeordneten Prozess des Ping jederzeit killen.

Als Anmerkung, wenn Du mal Zeit hast, schaue Dir Werkzeuge wie start-stop-daemon an. Diese können einem das Leben deutlich einfacher machen

0
fragwuerdiger81 
Fragesteller
 19.12.2018, 15:29
@KarlRanseierIII

Also ich komme da echt an meine Grenzen zumindest auch in diesem zeitlichen Rahmen :)
Ich habe nun alles sauber durchgetestet. Für das Skript-Überschneidungsproblem habe ich mir nun einen cron job gebastelt der um 59 23 * * * alle ping, ffmpeg und bash prozesse abschiesst und erste Tests bestätigen es klappt. In wie weit dies nun linuxtechnisch verwerflich ist weiß ich nicht aber es ist quick and dirty :)

Du hattest ja mal erwähnt, dass jemand ein Skript erstellt hatte um zu prüfen ob eine Datei wächst oder nicht. Ich glaube nun den Grund zu kennen oder zumindest einen der für mich auch Sinn ergeben würde. Es ist so das ping eine nicht unerhebliche Zeit benötigt nachdem ein Abbruch stattgefunden hat. Vom eigentlichen Abbruch bis zum nächsten Schritt vergehen so locker bis zu 30 Sekunden. Für den Fall das das Signal aber innerhalb dieser Zeit plötzlich wiederkommt, macht ping weiter mit seiner Aufgabe ungeachtet der Tatsache, dass ffmpeg längst abgerissen ist und nun kein neuer Prozess zum capturen gestaret wurde. Entweder ich bringe ping nun dazu nicht zu warten und direkt Abzubrechen / Abzugeben oder ich bastel mir auch noch dafür ein Skript, um das Risiko zu minimieren.
Ich denke aber das in den meisten Fällen, wenn überhaupt ein Abbruch zustande kommt, es länger als 30 Sekunden dauert bis das Signal wieder reinkommt und ping somit schon aufgegeben hat :)
Ist alles etwas tricky zumal die Kamera schon in den ersten Sekunden nach dem Anschalten wieder pingt.... Wie nützlich eine Steckdose mit Remote doch sein kann ^^

0

Der "sudo" wird halt das Problem sein, wenn der Call aus dem Background kommt.

Vermutlich bekommt er die Rechte nicht "einfach so", sondern will einen Passwort-Prompt o. ä. rauswerfen. Das läuft typischerweise über stderr. Und wenn Du z. B. aus einem Cronjob kommst, liegt auf stderr kein Input an. Wenn man hingegen von einer interaktiven Shell kommt, dann ist stderr auf das tty gebunden, d. h. es können selbst bei Redirections von stdin/stdout auf diesem Wege weiterhin "off-band"-artig z. B. Passwort-Prompts stattfinden.

fragwuerdiger81 
Fragesteller
 10.12.2018, 01:07

Ich muss dazu sagen ich bin Skript Anfänger und suche mir alle Codeschnipsel bei Google zusammen und passe für meine Bedürfnisse an. Bisher hat auch alles geklappt. Der Fehler tritt auch auf wenn ich nur eine echo Ausgabe verlange ohne ein sudo bash oder nur bash. ich habe schon mehrere Stunden einige Sachen probiert aber es kommt immer dieser Syntax Fehler oder Syntaxfehler beim unerwarteten Wort `fi' 

0