Câu hỏi Làm thế nào kịch bản Bash có thể giết chết phiên bản "đang ngủ" của chính nó đã chạy?


Chỉnh sửa Từ những bình luận bên dưới, tôi đã viết một lời giới thiệu khó hiểu / gây nhầm lẫn nên tôi đang viết lại nó.

Tôi có một tập lệnh bash được gọi là "khóa màn hình hẹn giờSau 30 phút, màn hình sẽ khóa màn hình và người dùng phải nhập mật khẩu của họ để mở khóa màn hình. Tuy nhiên, nếu người dùng thay đổi ý định hoặc họ muốn đặt lại hẹn giờ, họ sẽ có thể nhấp vào lối tắt trên màn hình một lần nữa và nó sẽ giết công việc đang chạy trước đó đang ngủ và đếm ngược.

Tôi đã thực hiện một thử nghiệm nhỏ và lỗi cho đến nay và nhấn một khối đường.

Đoạn mã có liên quan là:

pgrep tv-timer > ~/tv-timer.log
PID=$$ # Current Process ID

Sử dụng cat ~/tv-timer.log:

16382
20711

Một trong số này tương đương với "$ PID" ở trên nhưng bản kia là bản sao đang chạy mà tôi muốn sử dụng kill #####.

Cách tốt nhất để tìm ra một <> "$ PID" và giết nó là gì?

Lần đầu tiên tập lệnh được chạy chỉ có một mục nhập bằng "$ PID" mà tôi không muốn giết.

Cảm ơn bạn đã giúp đỡ!


Bản sao được đề xuất (Ngăn chặn chạy tập lệnh trùng lặp tại thời điểm sametime) là một vấn đề trong Cha mẹ và Đứa trẻ quy trình. Các câu trả lời được chấp nhận dài và phức tạp liên quan đến các kịch bản trình bao bọc và / hoặc nhiều dòng mã.

Giải pháp tìm kiếm ở đây là một dòng mã mới!

Thật vậy câu trả lời được chấp nhận ở đây dựa trên nỗ lực OP trùng lặp R DONG KHÔNG LÀM VIỆC!


4
2017-11-13 01:48


gốc


Có thể trùng lặp Ngăn chặn chạy tập lệnh trùng lặp tại thời điểm sametime - Sergiy Kolodyazhnyy
@Serg Tất cả các câu trả lời có (bao gồm cả bạn) liên quan đến các giải pháp phức tạp không giống như câu trả lời một dòng tôi đã hy vọng. OP có vẻ như có câu trả lời gần nhất với pkill -f $(pgrep run_scrapy.sh | grep -v $$) nhưng điều đó không làm việc cho anh ta trong môi trường cron. Đó là bản sao trông nhiều hơn một vấn đề cron hơn đơn giản này ít bash bộ đếm thời gian kịch bản. - WinEunuuchs2Unix
Có thể một cái gì đó như thế này có thể làm việc: PID=$(pgrep -n tv-timer) && kill -9 $(pgrep tv-timer | grep -v $PID)  Các -n bảo nó lấy cái mới nhất / cái hiện tại. - Terrance
@ Terrance Cảm ơn bạn đã đề xuất. Trên thực tế Serg và tôi chỉ làm việc nó ra trong phòng trò chuyện một vài phút trước đây. Các pgrep tv-timer | grep -v $$ dòng trả về ID tiến trình của phiên bản đang chạy trước đó. - WinEunuuchs2Unix
À, được rồi. Rất tốt. =) - Terrance


Các câu trả lời:


Vui lòng thay đổi dòng:

pgrep tv-timer | grep -v $$ > ~/tv-timer2.log

vào điều này:

pgrep tv-timer | grep -v ^$$$ > ~/tv-timer2.log

Trong thực tế, nếu một bộ đếm thời gian truyền hình có, giả sử, PID = 26019 và nên là 6019, sau đó grep sẽ mang lại một chuỗi rỗng, mà không phải là những gì bạn muốn.


4
2017-11-13 16:17



Nhưng tất cả các mã đang làm việc như là. Tôi đã thử nghiệm nó hàng chục lần. Kết quả được xác nhận bằng ps -aux | grep tv-timer từ dòng lệnh. BTW sau khi bạn có đủ danh tiếng, bạn sẽ có thể đăng câu trả lời này làm bình luận. Nếu bạn muốn tự mình kiểm tra toàn bộ tập lệnh, vui lòng xem: askubuntu.com/questions/837078/… - WinEunuuchs2Unix
grep là công cụ đối sánh dòng, vì vậy giả sử PID của bạn được đưa ra bởi $$ là 1234. Nếu grep thấy 1234 bất cứ đâu trên dòng, sau đó kịch bản sẽ bỏ qua một PID có thể là 51234 ví dụ. Điều đó có nghĩa, trường hợp khác của bạn sẽ không bị giết. Alessandro đúng - Sergiy Kolodyazhnyy


Đã dành nhiều giờ sau thỏ trắng vào các vũ trụ thay thế khác nhau, tôi thấy sau đây là phương pháp đáng tin cậy duy nhất là:

# If called a second time, kill the first version already running
kill $(pgrep -f "${0##*/}" | grep -v ^$$)

Nếu bạn quan tâm đến việc kiểm tra, hãy xem Lock Screen Timer mã trong Hỏi Ubuntu tại: (Ứng dụng sẽ khóa màn hình sau một khoảng thời gian nhất định cho Ubuntu)

Đoạn mã phiên bản sản xuất (TL; DR)

Đoạn mã thích hợp từ lock-screen-timer chương trình này là:

# Check if lock screen timer already running
pID=$(pgrep -f "${0##*/}") # All PIDs matching lock-screen-timer name
PREVIOUS=$(echo "$pID" | grep -v ^"$$") # Strip out this running copy ($$$)
if [ $PREVIOUS != "" ]; then
    zenity --info --title="Lock screen timer already running" --text="Previous lock screen timer has been terminated."
    kill "$PREVIOUS"
fi

pgrep -f "${0##*/}"

Điều này tìm thấy tất cả các lần xuất hiện của cùng một ID chương trình đang chạy ${0##*/}. Mặc dù tệp thi hành được gọi là ~/bin/lock-screen-timer một lối tắt trên màn hình được sử dụng để gọi nó. Điều đó có thể được đặt tên là "Khóa màn hình hẹn giờ" hoặc "Khóa màn hình hẹn giờ" hoặc "Nhắc tôi chu trình giặt". Nó không thể được mã hóa cứng vào chương trình như trong câu hỏi ban đầu.

Danh sách kết quả của quá trình id được đặt trong biến $pID

echo "$pID" | grep -v ^"$$"

Điều này có nội dung của $pID (tất cả các lần xuất hiện của lock-screen-timer, hoặc nó được đổi tên thành cắt ngắn trên màn hình) và đặt đường dẫn danh sách các id của quá trình vào lệnh tiếp theo bằng cách sử dụng đường ống (|) tính cách.

Lệnh tiếp theo grep -v loại bỏ khớp của ID quá trình đó $$ đó là ID tiến trình đang chạy. Củ cà rốt (^) yêu cầu grep đối sánh toàn bộ từ chứ không phải chuỗi ký tự. Ví dụ: id quá trình hiện tại có thể là 1518và phiên bản trước đó có thể là 11518, 21518 hoặc là 31518. Trong trường hợp đó, chỉ cần kết hợp trên 4 chữ số, quá trình id sẽ làm cho 3 kết quả phù hợp bởi vì 1518 là trong vòng 11518. Cà rốt phù hợp với từ 1518 <> 11518. Trong danh sách id quá trình, các từ được phân tách bằng dấu cách (trong một biến) hoặc các ký tự dòng mới (khi ps -aux lệnh hiển thị chúng trên màn hình).

Kết quả của hai lệnh này là ID tiến trình của lần chạy trước đó lock-screen-timer kịch bản. ID tiến trình được đưa vào biến $PREVIOUS. Nếu không có ID trước thì giá trị sẽ là "" (trường rỗng).

if [ $PREVIOUS != "" ]; then

Thử nghiệm này nếu $PREVIOUS Không bằng (!=) trường rỗng / trống "". Rõ ràng chúng ta chỉ có thể giết một ID tiến trình đang chạy trước đó nếu chúng ta có một!

zenity --info --title="Lock screen timer already running" ...

Khi chạy lối tắt trên màn hình, bạn không thể echo tin nhắn cho người dùng vì GUI sẽ không hiển thị chúng. Họ kết thúc bằng /var/log/syslog và bạn phải hiển thị chúng với cat hoặc là gedit, v.v.

zenity là một chương trình nhỏ để hiển thị hộp thoại và biểu mẫu từ bash đến GUI (Giao diện người dùng đồ họa), còn gọi là Desktop. Tin nhắn văn bản tiếp tục nói Bộ hẹn giờ màn hình khóa trước đã bị chấm dứt.. Điều này cho phép người dùng bắt đầu đếm ngược bộ đếm thời gian mới hoặc đơn giản là hủy. Về bản chất, gọi kịch bản lần thứ hai và hủy bỏ là cách bạn có thể giết tập lệnh đầu tiên đã chạy.

kill "$PREVIOUS"

Điều này chỉ đơn giản là giết chết phiên bản chạy trước đó mà chúng tôi muốn làm cho dù chúng tôi bắt đầu một phiên bản mới lock-screen-timer đếm ngược hay không. Điều này hoàn toàn khác với câu hỏi ban đầu bởi vì chúng tôi đã đặt kết quả của hai lệnh khó hiểu vào một biến duy nhất được gọi là $PREVIOUS.


3
2017-11-13 03:10