ubuntuusers.de

HOWTO: Timeout und selektives Kopieren

Status: Gelöst | Ubuntu-Version: Ubuntu 20.04 (Focal Fossa)
Antworten |

Emma2

Anmeldungsdatum:
28. Dezember 2018

Beiträge: 609

Ich warte auf mein Buch zur Shellprogrammierung, aber da ich so ungeduldig bin, frage ich vorab schon mal die Gurus hier. 🤓

Ich möchte in einem Shell-Skript verschiedene Dinge tun, von denen ich bei zweien nicht auf Anhieb eine Idee habe:

1. Ich muss in einer Schleife warten, bis ein "Ereignis" eintritt, möchte aber in dieser Schleife einen "ungefähren Timeout" haben (genaue Zeit ist unwichtig), also nicht unendlich lange warten. Gibt es hierfür Bordmittel? Oder muss man das simulieren (jemand anderes schlug mir eine definierte Zeit pro Schleifendurchlauf und einen Zähler vor)?

2. Ich möchte zwei "selektive" Kopiervorgänge starten, erstmal (a) "ein ganzes Verzeichnis bis auf Dateien mit einem bestimmten Namen/Extension" und dann (b) "alle Dateien (möglichst auch aus Unterverzeichnissen und in Unterverzeichnisse) bis auf eine Datei, deren Namen ich kenne". Gibt es also so etwas wie einen Positiv- oder Negativ-Filter für cp oder rsync?

Für die Frage nicht relevant, aber eventuell als Hintergrund: Ich bastele an einem Algorithmus zum Sichern meiner Virtualbox-VMs, und wir sind jetzt so weit, dass ich i) zunächst meine VM vom Host aus herunterfahren und auf deren abgeschlossenen Shutdown warten will (Frage 1), ii) danach alle Dateien bis auf virtuellen Platten aus dem Verzeichnis der VM auf mein NAS kopieren will (Frage 2a), iii) einen Snapshot erstellen und die VM wieder starten will und iv) abschließend die virtuellen Platten (bis auf die "nach dem Snapshot" bearbeitete) kopieren will (Frage 2b).

Doc_Symbiosis

Avatar von Doc_Symbiosis

Anmeldungsdatum:
11. Oktober 2006

Beiträge: 4453

Wohnort: Göttingen

Zu 2) Das geht beides mit der --exclude Option. Schau einfach mal in die Manpage von rsync.

Zu 1) Dafür musst Du ja gar keine Schleife bauen. Wenn Du in einem Skript den Befehl zum Shutdown auslöst, sollte der eigentlich eh warten, bis die VM runtergefahren ist. Du darfst den prozess natürlich nicht mit nohub oder & in den Hintergrund schicken...

Emma2

(Themenstarter)

Anmeldungsdatum:
28. Dezember 2018

Beiträge: 609

Doc_Symbiosis schrieb:

Zu 2) Das geht beides mit der --exclude Option. Schau einfach mal in die Manpage von rsync.

Sehe ich mir an, danke.

Doc_Symbiosis schrieb:

Zu 1) Dafür musst Du ja gar keine Schleife bauen. Wenn Du in einem Skript den Befehl zum Shutdown auslöst, sollte der eigentlich eh warten, bis die VM runtergefahren ist. Du darfst den prozess natürlich nicht mit nohub oder & in den Hintergrund schicken...

Nein, für Virtualbox gibt es das Tool vboxmanage, und das ist asynchron, kehrt also sofort zurück. Ich muss also danach "fragen", ob die VM down ist. Außerdem will ich ja gerade nicht unendlich lange warten, denn gerade eine Windowsmaschine wehrt sich auch schon mal gegen den Befehl, von außen herunter gefahren zu werden.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13207

Emma2 schrieb:

1. Ich muss in einer Schleife warten, bis ein "Ereignis" eintritt, möchte aber in dieser Schleife einen "ungefähren Timeout" haben (genaue Zeit ist unwichtig), also nicht unendlich lange warten. Gibt es hierfür Bordmittel? Oder muss man das simulieren (jemand anderes schlug mir eine definierte Zeit pro Schleifendurchlauf und einen Zähler vor)?

Das hängt von dem Ereignis ab, ob Du eine Schleife brauchst, wie ja schon Doc_Symbiosis anmerkte. Kannst Du das näher erläutern? Ansonsten geht natürlich ganz generisch ein Vergleich mit der Zeit:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/bin/sh

date

target=$(($(date +%s) + 15)) # timeout 15 seconds

# true as dummy check
while true && [ $(date +%s) -lt $target ]; do
  echo tick...
  sleep 1 # or something useful
done

date

Für die Frage nicht relevant, aber eventuell als Hintergrund: Ich bastele an einem Algorithmus zum Sichern meiner Virtualbox-VMs, und wir sind jetzt so weit, dass ich i) zunächst meine VM vom Host aus herunterfahren und auf deren abgeschlossenen Shutdown warten will (Frage 1),

Da müsstest Du in meinem Beispiel eine passende Prüfung statt true einbauen, z.B. kill -0 $pid_of_vm 2>/dev/null.

ii) danach alle Dateien bis auf virtuellen Platten aus dem Verzeichnis der VM auf mein NAS kopieren will (Frage 2a), iii) einen Snapshot erstellen und die VM wieder starten will und iv) abschließend die virtuellen Platten (bis auf die "nach dem Snapshot" bearbeitete) kopieren will (Frage 2b).

Ich verstehe den Ablauf nicht ganz: warum fährst Du nicht runter, erzeugst einen Snapshot, kopierst alle Dateien mit rsync -a ... und fährst dann wieder hoch?

PS: hast Du mal geprüft, ob der Befehl, der die VM herunterfährt vielleicht eine Option hat zu warten, bis sie unten ist? Das würde die Hexerei mit der separaten Prüfung sparen.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17621

Wohnort: Berlin

Emma2 schrieb:

Ich möchte in einem Shell-Skript verschiedene Dinge tun, von denen ich bei zweien nicht auf Anhieb eine Idee habe:

Pro Thread eine Frage ist nicht aus Quatsch eine Regel.

1. Ich muss in einer Schleife warten, bis ein "Ereignis" eintritt, möchte aber in dieser Schleife einen "ungefähren Timeout" haben (genaue Zeit ist unwichtig), also nicht unendlich lange warten.

Mit sleep kannst Du einstellen, dass Du 5.325 Sekunden schlafen willst, aber das schläft dann auch so lange, wenn Dein Ereignis längst eingetreten ist. Du kannst aber auch 5s oder 6s sagen, wenn 5.325 zu genau ist.

Oder mit einem Zufallsgenerator 15-25s warten:

1
n=$((RANDOM%10+15)) ; sleep $n

Gibt es hierfür Bordmittel? Oder muss man das simulieren (jemand anderes schlug mir eine definierte Zeit pro Schleifendurchlauf und einen Zähler vor)?

Wie stellst Du denn fest, dass das Ereignis eingetreten ist?

Ist das eine Endlosschleife, die nur prüft, ob das Ereignis eingetreten ist? Sowas frißt, ohne sleep, gerne 100% CPU oder doch nahezu 100% von einem Core.

Timeouts kann man auch mit timeout machen - wer hätte das gedacht?

Hier ist ein Code zum Demonstrieren/Testen: fortschrittsdots.sh:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash

dots () {
	while ( true ) 
	do
		sleep .2
		echo -n "." 
	done
}

work () {
	for n in {1..3}
	do
		echo $n
		sleep .8
	done
}

dots & 
mypid=$!
work 
echo "And the pid is: " $mypid
kill $((mypid))

Das malt Pünktchenn und Zeilenumbrüche in die Shell, etwa 3 Sekunden lang.

1
2
3
4
5
timeout 2s fortschrittsdots.sh 
1
...2
....3
..

Ausführung mit timeout 2s, wird vorzeitig abgewürgt, und hier mit 6s:

1
2
3
4
5
timeout 6s fortschrittsdots.sh 
1
...2
....3
....And the pid is:  6627

Läuft bis zum Ende durch.

Emma2

(Themenstarter)

Anmeldungsdatum:
28. Dezember 2018

Beiträge: 609

rklm schrieb:

Kannst Du das näher erläutern?

Klar, gerne: Ich rufe vboxmanage controlvm meineMaschine acpipowerbutton, was das Signal "Power-Button-pressed" an die VM sendet und sofort zurückkehrt (und auch nicht zum Warten anzuregen ist). Dann kann ich mit vboxmanage list runningvms feststellen, ob meineMaschine noch läuft. Da das Herunterfahren in der Regel ein paar Sekunden braucht, muss ich diese Abfrage mehrfach machen, bis sie "wahr" wird (Schleife), will aber auch nicht "unendlich" lange warten. Ich denke, Eure Tips helfen mir schon mal. Danke!

rklm schrieb:

Ich verstehe den Ablauf nicht ganz: warum fährst Du nicht runter, erzeugst einen Snapshot, kopierst alle Dateien mit rsync -a ... und fährst dann wieder hoch?

Genau das möchte ich vermeiden, weil das Kopieren einer großen virtuellen Platte doch eine ganze Zeit dauert. Ich möchte möglichst schnell wieder hochfahren und erst danach kopieren. (Deshalb haben wir im VB-Forum einen entsprechenden "Algorithmus" gebastelt, der genau das leistet. Den verrate ich gern, dachte nur, dass das nicht hierher gehört.)

rklm schrieb:

PS: hast Du mal geprüft, ob der Befehl, der die VM herunterfährt vielleicht eine Option hat zu warten, bis sie unten ist? Das würde die Hexerei mit der separaten Prüfung sparen.

Hat der Befehl nicht, würde mir aber auch nicht helfen (weil wie gesagt, ein Win-Gast manchmal gar nicht runterfährt... und obwohl ich mittlerweile nach und nach alles auf Linux umstelle, bleiben ein paar unvermeidliche MS-Artefakte)

Emma2

(Themenstarter)

Anmeldungsdatum:
28. Dezember 2018

Beiträge: 609

user_unknown schrieb:

Pro Thread eine Frage ist nicht aus Quatsch eine Regel.

Ok, sorry, dachte, dass ich nicht zu viele Threads starten solle... ☹

user_unknown schrieb:

Mit sleep kannst Du einstellen, dass Du 5.325 Sekunden schlafen willst, aber das schläft dann auch so lange, wenn Dein Ereignis längst eingetreten ist.

Na, so ein paar Sekunden machen mir kein Problem.

user_unknown schrieb:

Wie stellst Du denn fest, dass das Ereignis eingetreten ist?

Die angehaltene Maschine ist nicht mehr in der Liste der laufenden VMs.

user_unknown schrieb:

Ist das eine Endlosschleife, die nur prüft, ob das Ereignis eingetreten ist? Sowas frißt, ohne sleep, gerne 100% CPU oder doch nahezu 100% von einem Core.

sleep liest sich gut, danke!

user_unknown schrieb:

Timeouts kann man auch mit timeout machen - wer hätte das gedacht?

Hättich das gewusst, hättich nicht gefragt. 😛 (... und DHL hat mir gerade geschrieben, dass mein Buch später kommt, weil sie es neu verpacken müssen... 😮 wie gehen die schon wieder mit dem Zeug um... sorry, das war OT)

Dein Beispiel verstehe ich nicht auf Anhieb, aber ich lese gerade den Befehl timeout nach, das sieht mir prima aus. (Zu meiner Entschuldigung: ich komme von Windows, früher sogar von DOS, wo ein Batch was ganz was Tolles aber leider nicht so mächtig war, und beschäftige mich noch nicht sooo lange mit Linux, als das ich schon firm auf der Shell wäre - deshalb frage ich ja hier.)

Ich fasse zusammen:

  • Schleife verlangsamen mit sleep

  • Abbruch mit Zeitvergleich oder timeout

  • Selektives Kopieren mit rsync --exclude oder (gerade noch gefunden) cp -r <acc>ls -A grep -v "nichtKopieren"<acc> zielVerzeichnis/ (<acc> soll der Accent grave sein)

Danke für Eure Hilfe!

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17621

Wohnort: Berlin

Emma2 schrieb:

user_unknown schrieb:

Pro Thread eine Frage ist nicht aus Quatsch eine Regel.

Ok, sorry, dachte, dass ich nicht zu viele Threads starten solle... ☹

Du kannst eine Frage als gelöst markieren, wenn das Dein Eindruck ist, aber wie markierst Du eine Doppelfrage, wenn nur eine gelöst wurde?

Jmd., der über die Suchfunktion Deine Frage findet, und zwar mit einer ganzen Liste anderer Fragen, sieht in der Übersicht dann vielleicht, dass sie gelöst ist, obwohl sie das nicht ist, bzw. umgekehrt.

Außerdem beantwortet vielleicht ein Teil der User nur Frage 1, ein anderer nur Frage 2, vielleicht läuft einer der Threads ewig und man möchte ihn abbestellen, aber nicht Rückfragen zum anderen verpassen.

Dein Beispiel verstehe ich nicht auf Anhieb,

Mal laufen lassen?

aber ich lese gerade den Befehl timeout nach, das sieht mir prima aus. (Zu meiner Entschuldigung: ich komme von Windows, früher sogar von DOS, wo ein Batch was ganz was Tolles aber leider nicht so mächtig war, und beschäftige mich noch nicht sooo lange mit Linux, als das ich schon firm auf der Shell wäre - deshalb frage ich ja hier.)

Kein Problem, dafür sind wir ja da.

Ich könnte für solche Fragen wie timeout empfehlen, mit

1
2
apropos timeout
apt search timeout 

erst selbst nach sowas zu suchen, aber je nach dem dem ist das Stichwort, unter dem es gefunden würde, ein anderes oder man bekommt mehr Ergebnisse geliefert, als auf den Bildschirm passen. Manchmal hilft es einem aber schon weiter.

Ich fasse zusammen:

  • Schleife verlangsamen mit sleep

  • Abbruch mit Zeitvergleich oder timeout

Zeitvergleich fände ich auch umständlich.

1
for ((i=0; i < 25 && $(pidof xcalc)+0 > 0 ; i++)); do sleep 0.5; echo -n . ; done 

piof prüft, ob eine Prozessid vorhanden ist. Hier getestet mit xcalc, nicht mit einer VM. Wenn die VM-Verwaltung ein eigenes Kommando hat, um die PID oder etwas ähnliches zu liefern, könntest Du das analog in die Abbruchbedingung der for-Schleife einbauen.

Diese Schleife dort läuft 12.5s, wenn xcalc nicht beendet wird oder kürzer, wie es beendet wurde.

Das +0 ist nötig, weil pidof gar nichts liefert, wenn kein passender Prozess existiert.

Emma2

(Themenstarter)

Anmeldungsdatum:
28. Dezember 2018

Beiträge: 609

user_unknown schrieb:

Du kannst eine Frage als gelöst markieren, wenn das Dein Eindruck ist, aber wie markierst Du eine Doppelfrage, wenn nur eine gelöst wurde?

Sind ja für mich beide gelöst, denn ich weiß nun, wie ich weitermachen kann. 😛 (aber, ja, ich hab's verstanden: ein Thread pro Frage, wilco next time)

user_unknown schrieb:

erst selbst nach sowas zu suchen, aber je nach dem dem ist das Stichwort, unter dem es gefunden würde, ein anderes oder man bekommt mehr Ergebnisse geliefert, als auf den Bildschirm passen. Manchmal hilft es einem aber schon weiter.

Tat es eben nicht, deshalb habe ich ja nach der Suche hier gefragt (was natürlich nicht aus- oder sogar eher ein-schließt, dass ich ungeschickt gesucht habe 🤓 ) ... und als alter DOS/Win-Mann habe ich nicht zu hoffen gewagt, dass die Shell so mächtig ist (obwohl ich mich mittlerweile frage, wie ich es 30 Jahre mit Windows ausgehalten habe...)

user_unknown schrieb:

Wenn die VM-Verwaltung ein eigenes Kommando hat, um die PID oder etwas ähnliches zu liefern, könntest Du das analog in die Abbruchbedingung der for-Schleife einbauen.

Nö, das brauche ich nicht, denn das Verwaltungstool vboxmanage liefert mir direkt die Aussage, ob eine VM läuft oder nicht, wenn ich beispielsweise schreibe

1
2
3
4
if [ -n "$(vboxmanage list runningvms | grep -i $1)" ]
then
  vboxmanage snapshot $1 take $timestamp > NUL
fi

, dann nehme ich einen Snapshot nur dann, wenn die VM nicht läuft. Ich werde also wohl in einer while-Schleife mit sleep abfragen, ob die VM runtergefahren ist, und diese Schleife mit einem timeout umgeben.

Antworten |