Ermittelt, ob ein Werkzeug bereits ausgeführt wird, NUR jedoch für den aktuellen Benutzer

8

Bisher habe ich

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

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

Dies ist die Kurzversion der my-tool-Datei, ein ausführbares Bash-Skript

#!/bin/bash 

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

 ... if not running go on 

Nun muss ich jedoch eine einzige Instanz pro Benutzer und mehrere pro Maschine zulassen, sodass wir sogar 100 My-Tools gleichzeitig ausführen können, jedoch 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, schließt es sich selbst.

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

Wie geht das?

    
realtebo 26.07.2016, 14:04

4 Antworten

12

Verwenden Sie stattdessen pgrep :

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 überprüft, ob es bereits ausgeführt wird, können Sie $0 verwenden. Dies erweitert den Pfad des aktuellen Skripts (z. B. /home/username/bin/foo.sh ), wir benötigen jedoch nur foo.sh . Um dies zu erreichen, können wir alles bis zum letzten / entfernen, indem Sie die String-Manipulations-Tools von bash verwenden. a>: ${0##*/} . Dies bedeutet, dass wir Folgendes tun können:

## 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

Vielleicht möchten Sie auch die Verwendung von Lockfiles 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 26.07.2016, 14:07
7

Sie können pgrep fo finden, wenn ein Prozess von einem bestimmten Benutzer ausgeführt wird, und dann den Prozess 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 $USER wird auf den aktuell angemeldeten Benutzer erweitert, d. h. den Benutzer, der das Skript ausführt. Da wir nur daran interessiert sind, ob my-tool läuft oder nicht, genügt es, den Exit-Status direkt mit dem if -Konstrukt zu verwenden.

Verwenden Sie dieses Skript als Wrapper, um my-tool zu starten, und legen Sie fest, dass die Benutzer dies nur verwenden, oder benennen Sie es in my-tool um und benennen Sie das ursprüngliche my-tool in etwas anderes um (und ändern Sie auch den Namen im Skript).

    
heemayl 26.07.2016 14:18
2

Versuchen Sie es mit diesem Ausschnitt:

#!/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, pgrep|tr nicht zu schreiben, da dies zu einer gleichnamigen Shell führen würde.

    
rexkogitans 26.07.2016 16:37
2

Umfassen Sie den Befehl, den Sie ausführen möchten, in einer Gruppe, um sicherzustellen, dass jeweils nur eine Kopie ausgeführt wird. Verwenden Sie eine lock_file, die in der Home-Verzeichnisstruktur eines Benutzers gespeichert ist, sodass jeder Benutzer über eine eigene Sperrdatei verfügt. Zum Beispiel:

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

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

man flock enthält Anwendungsbeispiele

    
a guest 26.07.2016 17:48

Tags und Links