Ermitteln Sie, ob ein Tool bereits ausgeführt wird, jedoch NUR für den aktuellen Benutzer

8

Bis jetzt habe ich verwendet

pidof -o %PPID -x "my-tool"

Um die PID einer eventuell laufenden Instanz von my-tool zu erkennen.

Dies ist die Kurzversion von my-tool file, einem ausführbaren Bash-Skript

#!/bin/bash 

if pidof -o %PPID -x "my-tool"; then
   echo "Already running"
   exit 1
fi

 ... if not running go on 

Aber jetzt muss ich eine einzelne Instanz pro Benutzer und mehrere pro Computer zulassen , damit sogar 100 my-tool im selben Moment ausgeführt werden können, aber nur 1 pro Benutzer.

Beachten Sie, dass ich einen Test benötige, um so etwas wie einen Singleton zu erstellen. Wenn das Tool gestartet wird und eine andere Instanz ausgeführt wird, wird es sich selbst schließen.

Kurz gesagt: Ich brauche, dass ein Bash-Skript erkennen kann, ob es bereits für den aktuellen Benutzer ausgeführt wird, und in diesem Fall muss es beendet werden.

Wie man ?

Realtebo
quelle
Sie sollten nicht verwenden pidof, es gibt bessere Werkzeuge Lügepgrep
Katze

Antworten:

12

Verwenden Sie pgrepstattdessen:

pgrep -cxu $USER -f my-tool

Folgende Optionen werden verwendet:

   -c, --count
          Suppress  normal  output; instead print a count of matching pro
          cesses.  When count does not match anything, e.g. returns  zero,
          the command will return non-zero value.
   -x, --exact
          Only match processes whose names (or command line if -f is spec
          ified) exactly match the pattern.
   -u, --euid euid,...
          Only match processes whose effective user ID is listed.   Either
          the numerical or symbolical value may be used.

Wenn Sie dies in einem Bash-Skript verwenden möchten, das prüft, ob es bereits ausgeführt wird, können Sie es verwenden $0. Dies erweitert sich auf den Pfad des aktuellen Skripts (z. B. /home/username/bin/foo.sh), aber wir brauchen nur foo.sh. Um dies zu erreichen, können wir alles bis zum letzten Mal /mit den String-Manipulationswerkzeugen von bash entfernen : ${0##*/}. Das heißt, wir können so etwas tun:

## If there are more than 1 instances of the current script run
## by this user
if [[ $(pgrep -cxu "$USER" "${0##*/}") -gt 1 ]];
then
        echo "Script already running, exiting."
        exit
fi

Möglicherweise möchten Sie auch die Verwendung von Sperrdateien in Betracht ziehen:

## If the lock file exists
if [ -e /tmp/$USER.foo.lock ]; then
    ## Check if the PID in the lockfile is a running instance
    ## of foo.sh to guard against crashed scripts
    if ps $(cat /tmp/$USER.foo.lock) | grep foo.sh >/dev/null; then
        echo "Script foo.sh is already running, exiting"
        exit
    else
        echo "Lockfile contains a stale PID, continuing"
        rm /tmp/$USER.foo.lock 
    fi
fi
## Create the lockfile by printing the script's PID into it
echo $$ > /tmp/$USER.foo.lock

## Rest of the script here

## At the end, delete the lockfile
rm /tmp/$USER.foo.lock
Terdon
quelle
Lassen Sie uns diese Diskussion im Chat fortsetzen .
Terdon
1
Anstatt touch /tmp/$USER.foo.lockdie PID des Prozesses zu echo $$ >/tmp/$USER.foo.lockverwenden, könnte eine Logik enthalten sein, um zu testen, ob ein solcher Prozess tatsächlich existiert.
Monty Harder
@MontyHarder in der Tat sehr guter Vorschlag. Antwort bearbeitet, danke.
Terdon
@terdon, hatte ein Problem mit dem Handy, löschte diesen Kommentar in der nächsten Sekunde. Ich meinte $(< pidfile)statt $(cat pidfile).
SDKKS
7

Sie können verwenden, um pgrepherauszufinden, ob ein Prozess von einem bestimmten Benutzer ausgeführt wird, und den Prozess dann starten, wenn er nicht bereits vom Benutzer ausgeführt wird:

#!/bin/bash
if pgrep -u "$USER" my-tool &>/dev/null; then
    echo 'You already have my-tool running'
else
    /path/to/my_tool
fi

Die Umgebungsvariable $USERwird auf den aktuell angemeldeten Benutzer erweitert, dh auf den Benutzer, der das Skript ausführt. Da wir nur daran interessiert sind, ob das ausgeführt my-toolwird oder nicht, reicht es aus, nur den Exit-Status direkt mit dem ifKonstrukt zu verwenden.

Verwenden Sie dieses Skript als Wrapper zum Starten my-toolund lassen Sie die Benutzer nur dieses verwenden oder benennen Sie es um my-toolund benennen Sie das Original my-toolin etwas anderes um (und ändern Sie auch den Namen im Skript).

heemayl
quelle
Ich kann keinen Wrapper erstellen, lange Geschichte, ... wie kann ich die aktuelle Prozess-PID ausschließen?
Realtebo
@realtebo ummm..pID Bedeutung ausschließen?
Heemayl
2

Probieren Sie es mit diesem Snippet aus:

#!/bin/bash
MyProcessName=$(ps -p $$ -o args=)
Mypid=$$
AllPids=$(pgrep -fu "$(whoami)" "$MyProcessName")
AllPids=$(tr "\n" ' ' <<<"$AllPids")
Pids=$(sed "s/$Mypid//" <<<"$AllPids")
echo "$$: Instances including itself: $AllPids"
echo "$$: Instances different from itself: $Pids"

Es ist wichtig, nicht zu schreiben, pgrep|trda dies zu einer gleichnamigen Shell führen würde.

Rexkogitans
quelle
2

Schließen Sie den Befehl, den Sie ausführen möchten, in eine Herde ein, um sicherzustellen, dass jeweils nur eine Kopie ausgeführt wird. Verwenden Sie eine lock_file, die im Home-Verzeichnisbaum eines Benutzers gespeichert ist, damit jeder Benutzer seine eigene Sperrdatei hat. Zum Beispiel:

lockfile = "~/lockfile"
(
 if flock -n 200; then
    command
 else
    echo "Could not get lock $lock_file
 fi
) 200>$lock_file

'Befehl' kann ein beliebiger Bash-Befehl oder ein beliebiges Skript sein.

man flock gibt Anwendungsbeispiele

ein Gast
quelle
Wirklich, ich kannte das flockKommando überhaupt nicht
Realtebo