Phát hiện nếu một công cụ đã được thực thi nhưng CHỈ cho người dùng hiện tại


8

Cho đến bây giờ tôi đã sử dụng

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

Để phát hiện pid của một phiên bản cuối cùng đang chạy của công cụ của tôi.

Đây là phiên bản ngắn của tệp công cụ của tôi, tập lệnh bash thực thi

#!/bin/bash 

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

 ... if not running go on 

Nhưng bây giờ tôi cần cho phép một phiên bản duy nhất cho mỗi người dùng và nhiều người trên mỗi máy , vì vậy chúng tôi có thể có 100 công cụ của tôi chạy trong cùng một thời điểm, nhưng chỉ có 1 cho mỗi người dùng.

Lưu ý rằng tôi cần một bài kiểm tra để tạo ra một cái gì đó giống như một singleton. Nếu công cụ sẽ được khởi động và có một phiên bản khác đang chạy, nó sẽ tự đóng.

Tóm lại: Tôi cần một tập lệnh bash có thể phát hiện nếu nó đang chạy cho người dùng hiện tại và trong trường hợp này nó phải thoát.

Làm thế nào để ?


Bạn không nên sử dụng pidof, có những công cụ tốt hơn nói dốipgrep
mèo

Câu trả lời:


12

Sử dụng pgrepthay thế:

pgrep -cxu $USER -f my-tool

Các tùy chọn được sử dụng là:

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

Nếu bạn muốn sử dụng điều này trong một tập lệnh bash để kiểm tra xem nó đã chạy chưa, bạn có thể sử dụng $0. Điều này mở rộng đến đường dẫn của tập lệnh hiện tại (ví dụ /home/username/bin/foo.sh) nhưng chúng ta chỉ cần foo.sh. Để có được điều đó, chúng ta có thể xóa mọi thứ cho đến lần cuối /bằng cách sử dụng các công cụ thao tác chuỗi của bash : ${0##*/}. Điều này có nghĩa là chúng ta có thể làm một cái gì đó như:

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

Bạn cũng có thể muốn xem xét sử dụng lockfiles cho việc này:

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


1
Thay vì touch /tmp/$USER.foo.locktôi sẽ sử dụng PID của quá trình echo $$ >/tmp/$USER.foo.lockSau đó logic có thể được đưa vào để kiểm tra xem liệu quá trình đó có thực sự tồn tại hay không.
Monty Harder

@MontyHarder thực sự, đề nghị rất tốt. Trả lời chỉnh sửa, cảm ơn.
terdon

@terdon, có vấn đề với điện thoại di động, đã xóa nhận xét đó trong giây tiếp theo. Ý tôi là $(< pidfile)thay vì $(cat pidfile).
sdkks

7

Bạn có thể sử dụng để pgreptìm nếu một quy trình đang được thực thi bởi một người dùng cụ thể và sau đó bắt đầu quy trình nếu chưa chạy bởi người dùng:

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

Biến môi trường $USER, sẽ được mở rộng cho người dùng hiện đang đăng nhập, tức là người dùng đang chạy tập lệnh. Vì chúng ta chỉ quan tâm đến việc my-toolcó chạy hay không, nên chỉ cần sử dụng trạng thái thoát trực tiếp với ifcấu trúc là đủ.

Sử dụng tập lệnh này như một trình bao bọc để bắt đầu my-toolvà làm cho người dùng chỉ sử dụng hoặc đổi tên nó thành my-toolvà đổi tên ban đầu my-toolthành một cái khác (và thay đổi tên bên trong tập lệnh).


Tôi không thể tạo một trình bao bọc, lịch sử lâu dài, ... làm thế nào tôi có thể loại trừ quy trình PID hiện tại?
realtebo

@realtebo ummm..có nghĩa là PID?
heemayl

2

Hãy thử nó với đoạn trích này:

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

Điều quan trọng là không viết pgrep|trbởi vì điều này sẽ rẽ vào một vỏ có cùng tên.


2

Gói lệnh bạn muốn chạy trong một đàn để đảm bảo rằng chỉ có một bản sao chạy cùng một lúc. Sử dụng lock_file được lưu trữ trong cây thư mục chính của người dùng để mỗi người dùng có tệp khóa riêng. Ví dụ:

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

'Lệnh' có thể là bất kỳ lệnh bash hoặc tập lệnh nào.

man flock đưa ra ví dụ về cách sử dụng


Thực sự, tôi hoàn toàn không biết flocklệnh
realtebo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.