Forum: PC-Programmierung Hilfe bei einem Bash skript


von Martin L. (tempusertempuser)


Lesenswert?

Hallo,

ich habe ein skript geschrieben welches ein speziellen prozess beendet 
allerdings recht kompliziert meiner meinung nach...wie kann ich es 
verbessern, so das die ausgabe nicht erst in eine datei umgeleitet 
werden muss
1
#! /bin/bash
2
ps ax | grep 'openvpn --daemon --log /var/log/openvpn.log --config /home/' | grep -v 'grep' | awk '{print $1}' > test.test
3
while read line 
4
do 
5
   echo "$line"
6
   kill $line
7
done < test.test

von Klaus (feelfree)


Lesenswert?

killall ist dein Freund.

von Gerhard Z. (germel)


Lesenswert?

oder auch: man pkill

von Markus M. (adrock)


Lesenswert?

Die besseren Befehle wurden ja schon genannt.

Allgemein kannst Du in der Shell die Ausgaben von Befehlen in Variablen 
schreiben lassen, so sparst Du Dir die temporäre Datei. Das läuft unter 
dem Stichwort "Command Substitution".

Im Deinem Beispiel hätte man also z.B. sowas machen können:

PIDS=$( ps ax | grep 'openvpn --daemon --log /var/log/openvpn.log 
--config /home/' | grep -v 'grep' | awk '{print $1}' )

Danach hätte die Variable PID die gefundenen PIDs.

Über diese könntest Du dann iterieren mit:

for PID in $PIDS ; do
   kill $PID
done

Wenn man denn bei dem Konstrukt bleiben möchte, so hätte man es mit awk 
etwas einfacher bauen können, awk kann alles was Du brauchst.

Mit etwas vereinfachtem Pattern sieht das dann so aus:

PIDS=$( ps ax | awk '/[o]penvpn --daemon/ {print $1}' )

Die [] sorgen dafür, dass der awk Befehl selbst nicht matcht, da [o] im 
Pattern einem normalen "o" entspricht. Die Aktion in {} gibt die erste 
Spalte (PID) aus.

: Bearbeitet durch User
von Dieter D. (Firma: Hobbytheoretiker) (dieter_1234)


Lesenswert?

Indem Du über die Befehle einen String machst und mit "eval" in einen 
Befehl wandelst.

von Klaus (feelfree)


Lesenswert?

Markus M. schrieb:
> Mit etwas vereinfachtem Pattern sieht das dann so aus:
>
> PIDS=$( ps ax | awk '/[o]penvpn --daemon/ {print $1}' )

Die Variable mit anschliessender Auswertung kann man sich auch noch 
sparen und alles in eine Zeile packen:

kill `ps ax | awk '/[o]penvpn --daemon/ {print $1}'`

von Klaus (feelfree)


Lesenswert?

Dieter D. schrieb:
> Indem Du über die Befehle einen String machst und mit "eval" in
> einen
> Befehl wandelst.

Die Aufgabe bestand aber nicht darin, es noch komplizierter zu machen.

von Sebastian W. (wangnick)


Lesenswert?

Markus M. schrieb:
> awk kann alles was Du brauchst.

awk kann sogar system().

LG, Sebastian

von Daniel A. (daniel-a)


Lesenswert?

Falls du das für ein init Script brauchst, "--writepid" kann die pid in 
ein pidfile schreiben.
Oder falls du systemd hast, kannst du auch eine Systemd Unit dafür 
anlegen.

von Franko S. (frank_s866)


Lesenswert?

Klaus schrieb:
> Die Variable mit anschliessender Auswertung kann man sich auch noch
> sparen und alles in eine Zeile packen:

...und das kann man nochmal mit pgrep kürzer machen und sich das 
Frickelgeparse sparen.

: Bearbeitet durch User
von Ein T. (ein_typ)


Lesenswert?

Martin L. schrieb:
> ich habe ein skript geschrieben welches ein speziellen prozess beendet
> allerdings recht kompliziert meiner meinung nach...wie kann ich es
> verbessern, so das die ausgabe nicht erst in eine datei umgeleitet
> werden muss

Andere Teilnehmer des Threads haben Dir ja schon IMHO sehr brauchbare 
Ideen und Anregungen beschrieben. Mein Ratschlag wäre allerdings, Dein 
OpenVPN mit systemd zu verwalten. Wenn es ein normaler Benutzer starten 
und stoppen soll, so kann dies über das "NOPASSWD"-Feature von sudo(8) 
eingerichtet werden.

Viel Spaß und Erfolg! :-)

von Dieter D. (Firma: Hobbytheoretiker) (dieter_1234)


Lesenswert?

Klaus schrieb:
> Die Aufgabe bestand aber nicht darin, es noch komplizierter zu machen.

Der TO wollte keine Pipe über eine Datei als erstes.

Vermeidet eine Variable und zu 90% kann die Befehlssequenz von Markus 
übernommen werden. Copy Paste, etwas editieren, fertig. Und lernt dabei 
einen neuen shell Befehl.

Markus M. schrieb:
> z.B. sowas machen können:

von Martin L. (tempusertempuser)


Lesenswert?

Hallo vielen Dank fuer Eure Hilfen...

ich habe versucht dasselbe in python zu realisieren und bin soweit 
gekommen, dass mir die Zeile ausgegeben wird.
1
import subprocess
2
ps = subprocess.Popen(('ps', 'cax'), stdout=subprocess.PIPE)
3
output = ps.communicate()[0]
4
i = 0
5
for line in str(output).split("\\n"):
6
        if 'openvpn' in line:
7
                print(i)
8
                print(str(output).split("\\n")[i])
9
        i += 1


Ergebnis
1
   7836 ?        Ss     0:00 openvpn

wie kann ich nun diese Zeile in python spliten, so dass ich am ende auf 
die PID 7836 komme?

Danke fuer die Hilfe

von Norbert (der_norbert)


Lesenswert?

Martin L. schrieb:
> wie kann ich nun diese Zeile in python spliten,

Ernsthaft? Also im Sinne von: ERNSTHAFT?

von Franko S. (frank_s866)


Lesenswert?

Norbert schrieb:
> Ernsthaft? Also im Sinne von: ERNSTHAFT?

Warte mal was noch kommt. In Dockercontainer werfen, vorher noch nen 
Webservice daraus machen, ...

von Alexander (alecxs)


Lesenswert?

Martin L. schrieb:
> Hilfe bei einem Bash skript

Martin L. schrieb:
> wie kann ich nun diese Zeile in python spliten

Ich würde versuchen ein Shell Skript so zu schreiben dass es auch auf 
Systemen läuft wo weder Bash, Awk noch Python vorhanden ist.

von Norbert (der_norbert)


Lesenswert?

Franko S. schrieb:
> Warte mal was noch kommt. In Dockercontainer werfen, vorher noch nen
> Webservice daraus machen, ...

Im Sinne einer echten Rube-Goldberg-Maschine sollte man darüber 
nachdenken alle PIDs mit einem Projektor an die Wand zu strahlen. Dann 
mit einer Roboter-gesteuerten Kamera und einem OpenCV System einzeln 
anfahren und ablesen.

: Bearbeitet durch User
von Klaus (feelfree)


Lesenswert?

Dieter D. schrieb:
> Indem Du über die Befehle einen String machst und mit "eval" in
> einen
> Befehl wandelst.

Zeig mal.

von Foobar (asdfasd)


Lesenswert?

Alexander schrieb:
> Ich würde versuchen ein Shell Skript so zu schreiben dass es auch auf
> Systemen läuft wo weder Bash, Awk noch Python vorhanden ist.

sh only (außer ps und kill):
1
#!/bin/sh
2
ps axww | while read pid tty stat time cmd; do
3
    case "$cmd" in
4
        "openvpn --daemon"*) echo kill "$pid";;
5
    esac
6
done

Das "read"-Kommando, insb in Kombination mit "while", wird mMn viel zu 
selten benutzt.  Ebenso "case" für's Pattern/String-matching.  So eine 
Schleife in sh ist nicht allzu schnell (deswegen wurde ja awk 
entwickelt), in solch einem Fall aber akzeptabel.  Der Kompatibilität 
abträglich ist der ps, der dummerweise ziemlich systemspezifisch ist. 
Da könnte man auf die Idee kommen, direkt /proc/<pid>/cmdline zu 
benutzen - es wird dadurch aber eher schlimmer.


PS: Eh, zum "scharfmachen" das "echo" entfernen.

: Bearbeitet durch User
von Alexander (alecxs)


Lesenswert?

Foobar schrieb:
> while read pid tty stat time cmd

ist auf jeden Fall leserlich und leicht auf das jeweilige ps zu 
adaptieren

von Franko S. (frank_s866)


Lesenswert?

Alexander schrieb:
> ist auf jeden Fall leserlich und leicht auf das jeweilige ps zu
> adaptieren
Das ps macht mehr Ärger als es auf den ersten Blick aussieht, vor allem 
ist es völlig überflüssig. Dazu der Subprozess durch die pipe, auch 
immer ein lustiger Quell an dubiosem Verhalten wenn man nicht weiss was 
man da eigentlich macht und so ein Script später erweitert. So einen 
Schrott musste ich jahrelang von Kollegen geradebiegen. Das ganze Ding 
lässt sich auf einen Einzeiler eindampfen wenn man pgrep verwendet.

von Alexander (alecxs)


Lesenswert?

bis auf AIX scheint pgrep auch überall Standard zu sein, ist noch 
eleganter
1
pgrep openvpn | xargs kill

: Bearbeitet durch User
von Dieter D. (Firma: Hobbytheoretiker) (dieter_1234)


Lesenswert?

Franko S. schrieb:
> Das ganze Ding lässt sich auf einen Einzeiler eindampfen wenn man pgrep
> verwendet.

Das von Dir ist natuerlich kuerzer, von Klaus auch.

Franko S. schrieb:
> ein lustiger Quell an dubiosem Verhalten

Wegen moeglicher Fehler verwende ich manchmal den Befehl eval um vorher 
den zusammengesetzten Befehl am Bildschirm ausgeben zu lassen.

von Ein T. (ein_typ)


Lesenswert?

Martin L. schrieb:
> ich habe versucht dasselbe in python zu realisieren und bin soweit
> gekommen, dass mir die Zeile ausgegeben wird.

Pythons "psutil" installieren (virtualenv oder Systempaket), dann:
1
#!/usr/bin/env python
2
import psutil
3
4
def main():
5
    for proc in psutil.process_iter():
6
        if 'openvpn' in proc.name():
7
            proc.kill()
8
9
if __name__ == '__main__':
10
    main()

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.