Mendeteksi jika alat sudah dalam pelaksanaan tetapi HANYA untuk pengguna saat ini

8

Sampai sekarang saya menggunakan

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

Untuk mendeteksi pid dari instance my-tool yang akhirnya berjalan.

Ini adalah versi singkat dari file alat saya, skrip bash yang dapat dieksekusi

#!/bin/bash 

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

 ... if not running go on 

Tapi sekarang saya harus mengizinkan satu instance per pengguna dan beberapa per mesin , sehingga kami dapat menjalankan bahkan 100 perangkat saya pada saat yang sama, tetapi hanya 1 per pengguna.

Perhatikan bahwa saya perlu tes untuk membuat sesuatu seperti singleton. Jika alat akan dimulai dan ada contoh lain yang menjalankannya akan menutup sendiri.

Singkatnya: Saya perlu agar skrip bash dapat mendeteksi jika skrip tersebut sudah berjalan untuk pengguna saat ini dan dalam hal ini harus keluar.

Bagaimana caranya?

realtebo
sumber
Anda seharusnya tidak menggunakan pidof, ada alat yang lebih baik berbohongpgrep
kucing

Jawaban:

12

Gunakan pgrepsebaliknya:

pgrep -cxu $USER -f my-tool

Opsi yang digunakan adalah:

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

Jika Anda ingin menggunakan ini dalam skrip bash yang memeriksa apakah sudah berjalan, Anda bisa menggunakannya $0. Ini memperluas ke jalan naskah saat ini (misalnya /home/username/bin/foo.sh) tetapi kita hanya perlu foo.sh. Untuk mendapatkan itu, kita dapat menghapus segala sesuatu sampai yang terakhir /menggunakan bash alat manipulasi string : ${0##*/}. Ini berarti kita dapat melakukan sesuatu seperti:

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

Anda mungkin juga ingin mempertimbangkan menggunakan file kunci untuk ini:

## 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
sumber
1
Daripada touch /tmp/$USER.foo.locksaya akan menggunakan PID dari proses echo $$ >/tmp/$USER.foo.lockKemudian logika dapat dimasukkan untuk menguji apakah proses tersebut benar-benar ada.
Monty Harder
@MontyHarder memang, saran yang sangat bagus. Jawaban diedit, terima kasih.
terdon
@terdon, punya masalah dengan ponsel, menghapus komentar itu di detik berikutnya. Maksud saya $(< pidfile)alih-alih $(cat pidfile).
SDK
7

Anda dapat menggunakan pgrepfo find jika suatu proses sedang dijalankan oleh pengguna tertentu dan kemudian memulai proses jika belum berjalan oleh pengguna:

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

Variabel lingkungan $USER,, akan diperluas ke pengguna yang saat ini masuk yaitu pengguna yang menjalankan skrip. Karena kami hanya tertarik pada apakah my-toolberjalan atau tidak, jadi hanya menggunakan status keluar secara langsung dengan ifkonstruk sudah cukup.

Gunakan skrip ini sebagai pembungkus untuk memulai my-tooldan buat pengguna hanya menggunakan ini atau ganti namanya my-tooldan ganti nama aslinya my-toolmenjadi yang lain (dan ubah nama di dalam skrip juga).

heemayl
sumber
Saya tidak bisa membuat pembungkus, sejarah panjang, ... bagaimana saya bisa mengecualikan PID proses saat ini?
realtebo
@realtebo ummm..mencakup arti PID?
heemayl
2

Cobalah dengan cuplikan ini:

#!/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"

Penting untuk tidak menulis pgrep|trkarena ini akan bercabang menjadi shell bernama sama.

rexkogitans
sumber
2

Bungkus perintah yang ingin Anda jalankan dalam kawanan untuk memastikan bahwa hanya satu salinan yang berjalan pada satu waktu. Gunakan lock_file yang disimpan dalam pohon direktori home pengguna sehingga setiap pengguna memiliki file kunci mereka sendiri. Sebagai contoh:

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

'command' dapat berupa perintah atau skrip bash.

man flock memberikan contoh penggunaan

seorang tamu
sumber
Sungguh, saya tidak tahu flockperintah sama sekali
realtebo