Khóa chính xác trong shell script?


66

Đôi khi bạn phải đảm bảo rằng chỉ có một phiên bản của tập lệnh shell đang chạy cùng một lúc.

Ví dụ, một công việc định kỳ được thực hiện thông qua crond không tự cung cấp khóa (ví dụ: crois Solaris mặc định).

Một mô hình phổ biến để thực hiện khóa là mã như thế này:

#!/bin/sh
LOCK=/var/tmp/mylock
if [ -f $LOCK ]; then            # 'test' -> race begin
  echo Job is already running\!
  exit 6
fi
touch $LOCK                      # 'set'  -> race end
# do some work
rm $LOCK

Tất nhiên, mã như vậy có một điều kiện chủng tộc. Có một cửa sổ thời gian trong đó việc thực thi hai trường hợp có thể tiến lên sau dòng 3 trước khi có thể chạm vào $LOCKtệp.

Đối với một công việc định kỳ, điều này thường không phải là vấn đề vì bạn có một khoảng thời gian giữa hai lần gọi.

Nhưng mọi thứ có thể sai - ví dụ như khi lockfile nằm trên máy chủ NFS - bị treo. Trong trường hợp đó, một số công việc cron có thể chặn trên dòng 3 và xếp hàng. Nếu máy chủ NFS là hoạt động trở lại sau đó bạn có bầy sấm công việc chạy song song.

Tìm kiếm trên web tôi đã tìm thấy công cụ lockrun có vẻ như là một giải pháp tốt cho vấn đề đó. Với nó, bạn chạy một kịch bản cần khóa như thế này:

$ lockrun --lockfile=/var/tmp/mylock myscript.sh

Bạn có thể đặt nó trong một trình bao bọc hoặc sử dụng nó từ crontab của bạn.

Nó sử dụng lockf()(POSIX) nếu có và quay lại flock()(BSD). Và lockf()hỗ trợ trên NFS nên tương đối rộng rãi.

Có những lựa chọn thay thế lockrun?

Còn các cron daemon khác thì sao? Có crond phổ biến nào hỗ trợ khóa theo cách lành mạnh không? Nhìn nhanh vào trang con người của Vixie Crond (mặc định trên các hệ thống Debian / Ubuntu) không hiển thị bất cứ điều gì về việc khóa.

Nó sẽ là một ý tưởng tốt để bao gồm một công cụ như lockrunvào coreutils ?

Theo tôi nó thực hiện một chủ đề rất giống với timeout, nicevà bạn bè.


4
Tiếp theo, và vì lợi ích của những người khác có thể xem xét mô hình ban đầu của bạn Đủ tốt (tm), mã shell đó có thể sẽ bẫy TATE để xóa tệp khóa của nó khi killed; và nó có vẻ là một thực hành tốt để lưu trữ pid của chính mình trong kho khóa, thay vì chỉ chạm vào nó.
Ulrich Schwarz


@Shawn, không thực sự, không đề cập đến crond và NFS.
maxschlepzig

câu hỏi liên quan trên SO: stackoverflow.com/questions/185451/ từ
maxschlepzig

1
@Ulrich rất muộn màng, việc lưu trữ một PID trong một tệp khóa NFS thêm rất ít giá trị. Ngay cả việc thêm tên máy chủ vẫn không thực sự giúp ích cho việc kiểm tra quy trình trực tiếp
roaima

Câu trả lời:


45

Đây là một cách khác để thực hiện khóa trong shell script có thể ngăn điều kiện cuộc đua mà bạn mô tả ở trên, trong đó hai công việc có thể vượt qua cả dòng 3. noclobberTùy chọn sẽ hoạt động trong ksh và bash. Đừng sử dụng set noclobbervì bạn không nên viết kịch bản trong csh / tcsh. ;)

lockfile=/var/tmp/mylock

if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then

        trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT

        # do stuff here

        # clean up after yourself, and release your trap
        rm -f "$lockfile"
        trap - INT TERM EXIT
else
        echo "Lock Exists: $lockfile owned by $(cat $lockfile)"
fi

YMMV có khóa trên NFS (bạn biết đấy, khi máy chủ NFS không truy cập được), nhưng nói chung, nó mạnh hơn nhiều so với trước đây. (10 năm trước)

Nếu bạn có các công việc định kỳ làm cùng một việc cùng một lúc, từ nhiều máy chủ, nhưng bạn chỉ cần 1 cá thể để thực sự chạy, thì những thứ như thế này có thể phù hợp với bạn.

Tôi không có kinh nghiệm với lockrun, nhưng có một môi trường khóa được cài đặt sẵn trước khi tập lệnh thực sự chạy có thể giúp ích. Hoặc nó có thể không. Bạn chỉ đang thiết lập thử nghiệm cho lockfile bên ngoài tập lệnh của mình trong một trình bao bọc, và theo lý thuyết, bạn không thể đạt được điều kiện cuộc đua giống nhau nếu hai công việc được gọi bằng locksl cùng một lúc, giống như với 'bên trong- giải pháp kịch bản?

Khóa tệp là khá nhiều hành vi của hệ thống danh dự, và bất kỳ tập lệnh nào không kiểm tra sự tồn tại của khóa trước khi chạy sẽ làm bất cứ điều gì chúng sẽ làm. Chỉ bằng cách đưa vào bài kiểm tra lockfile và hành vi đúng đắn, bạn sẽ giải quyết được 99% các vấn đề tiềm ẩn, nếu không phải là 100%.

Nếu bạn gặp phải tình trạng cuộc đua lockfile rất nhiều, đó có thể là một dấu hiệu của một vấn đề lớn hơn, như việc công việc của bạn không đúng thời gian, hoặc có lẽ nếu khoảng thời gian không quan trọng bằng công việc hoàn thành, có lẽ công việc của bạn phù hợp hơn để được trình bày .


EDIT DƯỚI ĐÂY - 2016-05-06 (nếu bạn đang sử dụng KSH88)


Dựa trên nhận xét của @Clint Pachl bên dưới, nếu bạn sử dụng ksh88, hãy sử dụng mkdirthay vì noclobber. Điều này chủ yếu giảm nhẹ một điều kiện chủng tộc tiềm năng, nhưng không hoàn toàn hạn chế nó (mặc dù rủi ro là rất nhỏ). Để biết thêm thông tin đọc liên kết mà Clint đăng dưới đây .

lockdir=/var/tmp/mylock
pidfile=/var/tmp/mylock/pid

if ( mkdir ${lockdir} ) 2> /dev/null; then
        echo $$ > $pidfile
        trap 'rm -rf "$lockdir"; exit $?' INT TERM EXIT
        # do stuff here

        # clean up after yourself, and release your trap
        rm -rf "$lockdir"
        trap - INT TERM EXIT
else
        echo "Lock Exists: $lockdir owned by $(cat $pidfile)"
fi

Và, như một lợi thế bổ sung, nếu bạn cần tạo tmpfiles trong tập lệnh của mình, bạn có thể sử dụng lockdirthư mục cho chúng, biết rằng chúng sẽ được dọn sạch khi tập lệnh thoát.

Đối với bash hiện đại hơn, phương pháp noclobber ở đầu nên phù hợp.


1
Không, với tính năng khóa, bạn không gặp sự cố - khi máy chủ NFS bị treo, tất cả các cuộc gọi khóa sẽ bị treo (ít nhất) trong lockf()cuộc gọi hệ thống - khi sao lưu tất cả các quy trình được nối lại nhưng chỉ một quy trình sẽ giành được khóa. Không có điều kiện chủng tộc. Tôi không gặp phải những vấn đề như vậy với cronjobs - điều ngược lại là vậy - nhưng đây là vấn đề khi nó đánh vào bạn, nó có khả năng tạo ra rất nhiều nỗi đau.
maxschlepzig

1
Tôi đã chấp nhận câu trả lời này bởi vì phương pháp này là an toàn và cho đến nay là phương pháp thanh lịch nhất. Tôi đề xuất một biến thể nhỏ: set -o noclobber && echo "$$" > "$lockfile"để có được một dự phòng an toàn khi vỏ không hỗ trợ tùy chọn noclobber.
maxschlepzig

3
Câu trả lời hay, nhưng bạn cũng nên 'giết -0' giá trị trong lockfile để đảm bảo rằng quy trình tạo khóa vẫn tồn tại.
Nigel Horne

1
Các noclobbertùy chọn có thể dễ bị điều kiện cuộc đua. Xem mywiki.wooledge.org/BashFAQ/045 để biết một số thực phẩm để suy nghĩ.
Clint Pachl

2
Lưu ý: sử dụng noclobber(hoặc -C) trong ksh88 không hoạt động vì ksh88 không sử dụng O_EXCLcho noclobber. Nếu bạn đang chạy với lớp vỏ mới hơn, bạn có thể ổn ...
jrw32982

14

Tôi thích sử dụng các liên kết cứng.

lockfile=/var/lock/mylock
tmpfile=${lockfile}.$$
echo $$ > $tmpfile
if ln $tmpfile $lockfile 2>&-; then
    echo locked
else
    echo locked by $(<$lockfile)
    rm $tmpfile
    exit
fi
trap "rm ${tmpfile} ${lockfile}" 0 1 2 3 15
# do what you need to

Liên kết cứng là nguyên tử trên NFS và phần lớn, mkdir cũng vậy . Sử dụng mkdir(2)hoặc link(2)là như nhau, ở mức độ thực tế; Tôi chỉ thích sử dụng các liên kết cứng vì việc triển khai NFS cho phép liên kết cứng nguyên tử nhiều hơn nguyên tử mkdir. Với các bản phát hành hiện đại của NFS, bạn không cần phải lo lắng khi sử dụng.


12

Tôi hiểu đó mkdirlà nguyên tử, nên có lẽ:

lockdir=/var/tmp/myapp
if mkdir $lockdir; then
  # this is a new instance, store the pid
  echo $$ > $lockdir/PID
else
  echo Job is already running, pid $(<$lockdir/PID) >&2
  exit 6
fi

# then set traps to cleanup upon script termination 
# ref http://www.shelldorado.com/goodcoding/tempfiles.html
trap 'rm -r "$lockdir" >/dev/null 2>&1' 0
trap "exit 2" 1 2 3 13 15

Ok, nhưng tôi không thể tìm thấy thông tin cho dù mkdir()trên NFS (> = 3) được chuẩn hóa thành nguyên tử.
maxschlepzig

2
@maxschlepzig RFC 1813 không gọi rõ ràng mkdirlà nguyên tử (nó dành cho rename). Trong thực tế, người ta biết rằng một số thực hiện là không. Liên quan: một chủ đề thú vị, bao gồm cả sự đóng góp của tác giả của vòm GNU .
Gilles 'SO- ngừng trở nên xấu xa'

8

Một cách dễ dàng là sử dụng lockfilethường đến với procmailgói.

LOCKFILE="/tmp/mylockfile.lock"
# try once to get the lock else exit
lockfile -r 0 "$LOCKFILE" || exit 0

# here the actual job

rm -f "$LOCKFILE"

5

semvốn là một phần của các parallelcông cụ GNU có thể là thứ bạn đang tìm kiếm:

sem [--fg] [--id <id>] [--semaphoretimeout <secs>] [-j <num>] [--wait] command

Như trong:

sem --id my_semaphore --fg "echo 1 ; date ; sleep 3" &
sem --id my_semaphore --fg "echo 2 ; date ; sleep 3" &
sem --id my_semaphore --fg "echo 3 ; date ; sleep 3" &

xuất ra:

1
Thu 10 Nov 00:26:21 UTC 2016
2
Thu 10 Nov 00:26:24 UTC 2016
3
Thu 10 Nov 00:26:28 UTC 2016

Lưu ý rằng đơn hàng không được đảm bảo. Ngoài ra, đầu ra không được hiển thị cho đến khi nó kết thúc (gây khó chịu!). Nhưng ngay cả như vậy, đó là cách ngắn gọn nhất mà tôi biết để bảo vệ chống lại việc thực hiện đồng thời, mà không phải lo lắng về các khóa và thử lại và dọn dẹp.


Liệu khóa được cung cấp bởi semxử lý bị bắn hạ giữa thực hiện?
roaima

2

Tôi sử dụng dtach.

$ dtach -n /tmp/socket long_running_task ; echo $?
0
$ dtach -n /tmp/socket long_running_task ; echo $?
dtach: /tmp/socket: Address already in use
1

1

Tôi sử dụng công cụ dòng lệnh "bầy" để quản lý các khóa trong tập lệnh bash của tôi, như được mô tả ở đâyđây . Tôi đã sử dụng phương pháp đơn giản này từ trang đàn, để chạy một số lệnh trong ...

   (
     flock -n 9
     # ... commands executed under lock ...
   ) 9>/var/lock/mylockfile

Trong ví dụ đó, nó không thành công với mã thoát là 1 nếu nó không thể có được lockfile. Nhưng đàn cũng có thể được sử dụng theo những cách không yêu cầu chạy lệnh trong lớp vỏ phụ :-)


3
Cuộc flock()gọi hệ thống không hoạt động trên NFS .
maxschlepzig

1
BSD có một công cụ tương tự, "lockf".
dubiousjim

2
@dubiousjim, BSD lockf cũng gọi flock()và do đó có vấn đề với NFS. Btw, trong khi đó, flock () trên Linux bây giờ quay trở lại fcntl()khi tệp được đặt trên ngàm NFS, do đó, trong môi trường NFS chỉ dành cho Linux flock()hiện hoạt động trên NFS.
maxschlepzig

1

Đừng sử dụng một tập tin.

Nếu tập lệnh của bạn được thực thi như thế này, vd:

bash my_script

Bạn có thể phát hiện nếu nó đang chạy bằng cách sử dụng:

running_proc=$(ps -C bash -o pid=,cmd= | grep my_script);
if [[ "$running_proc" != "$$ bash my_script" ]]; do 
  echo Already locked
  exit 6
fi

Hừm, mã kiểm tra ps chạy từ bên trong my_script? Trong trường hợp một phiên bản khác đang chạy - không running_procchứa hai dòng khớp? Tôi thích ý tưởng này, nhưng tất nhiên - bạn sẽ nhận được kết quả sai khi một người dùng khác đang chạy một tập lệnh có cùng tên ...
maxschlepzig

3
Nó cũng bao gồm một điều kiện cuộc đua: nếu 2 trường hợp thực hiện song song dòng đầu tiên thì không có trường hợp nào có 'khóa' và cả hai thoát với trạng thái 6. Đây sẽ là một kiểu bỏ đói một vòng . Btw, tôi không chắc tại sao bạn sử dụng $!thay vì $$trong ví dụ của bạn.
maxschlepzig

@maxschlepzig thực sự xin lỗi về $ không chính xác! so với $$
Frogstarr78

@maxschlepzig để xử lý nhiều người dùng đang chạy tập lệnh thêm euser = vào đối số -o.
ếchstarr78

@maxschlepzig để ngăn nhiều dòng, bạn cũng có thể thay đổi đối số thành grep hoặc "bộ lọc" bổ sung (ví dụ grep -v $$). Về cơ bản, tôi đã cố gắng cung cấp một cách tiếp cận khác cho vấn đề.
ếchstarr78

1

Để sử dụng thực tế, bạn nên sử dụng câu trả lời bình chọn hàng đầu .

Tuy nhiên, tôi muốn thảo luận về một số cách tiếp cận bị hỏng và bán khả thi khác nhau bằng cách sử dụng psvà nhiều cảnh báo họ có, vì tôi cứ thấy mọi người sử dụng chúng.

Câu trả lời này thực sự là câu trả lời cho "Tại sao không sử dụng psgrepxử lý khóa trong vỏ?"

Cách tiếp cận bị hỏng # 1

Đầu tiên, một cách tiếp cận được đưa ra trong một câu trả lời khác có một vài upvote mặc dù thực tế là nó không (và không bao giờ có thể) hoạt động và rõ ràng không bao giờ được thử nghiệm:

running_proc=$(ps -C bash -o pid=,cmd= | grep my_script);
if [[ "$running_proc" != "$$ bash my_script" ]]; do 
  echo Already locked
  exit 6
fi

Chúng ta hãy sửa các lỗi cú pháp và các psđối số bị hỏng và nhận:

running_proc=$(ps -C bash -o pid,cmd | grep "$0");
echo "$running_proc"
if [[ "$running_proc" != "$$ bash $0" ]]; then
  echo Already locked
  exit 6
fi

Kịch bản này sẽ luôn thoát 6, mọi lúc, bất kể bạn chạy nó như thế nào.

Nếu bạn chạy nó với ./myscript, thì psđầu ra sẽ chỉ 12345 -bash, không khớp với chuỗi yêu cầu 12345 bash ./myscript, do đó sẽ thất bại.

Nếu bạn chạy nó với bash myscript, mọi thứ trở nên thú vị hơn. Quá trình bash dĩa để chạy các đường ống, và các con shell chạy psgrep. Cả vỏ ban đầu và vỏ con sẽ hiển thị ở psđầu ra, đại loại như thế này:

25793 bash myscript
25795 bash myscript

Đó không phải là đầu ra dự kiến $$ bash $0, vì vậy tập lệnh của bạn sẽ thoát.

Cách tiếp cận bị hỏng # 2

Bây giờ trong tất cả sự công bằng cho người dùng đã viết cách tiếp cận bị hỏng # 1, tôi đã làm một cái gì đó tương tự khi lần đầu tiên tôi thử điều này:

if otherpids="$(pgrep -f "$0" | grep -vFx "$$")" ; then
  echo >&2 "There are other copies of the script running; exiting."
  ps >&2 -fq "${otherpids//$'\n'/ }" # -q takes about a tenth the time as -p
  exit 1
fi

Điều này gần như hoạt động. Nhưng thực tế của việc chạy để chạy đường ống ném điều này ra. Vì vậy, cái này sẽ luôn luôn thoát.

Cách tiếp cận không đáng tin cậy # 3

pids_this_script="$(pgrep -f "$0")"
if not_this_process="$(echo "$pids_this_script" | grep -vFx "$$")"; then
  echo >&2 "There are other copies of this script running; exiting."
  ps -fq "${not_this_process//$'\n'/ }"
  exit 1
fi

Phiên bản này tránh vấn đề giả mạo đường ống trong cách tiếp cận # 2 bằng cách trước tiên nhận tất cả các PID có tập lệnh hiện tại trong các đối số dòng lệnh của chúng, sau đó lọc riêng pidlist đó để bỏ qua PID của tập lệnh hiện tại.

Điều này có thể hoạt động ... cung cấp không có quy trình nào khác có dòng lệnh khớp với $0và cung cấp tập lệnh luôn được gọi theo cùng một cách (ví dụ: nếu nó được gọi với một đường dẫn tương đối và sau đó là một đường dẫn tuyệt đối, thì trường hợp sau sẽ không chú ý đến trước ).

Cách tiếp cận không đáng tin cậy # 4

Vậy điều gì sẽ xảy ra nếu chúng ta bỏ qua việc kiểm tra dòng lệnh đầy đủ, vì điều đó có thể không cho thấy tập lệnh thực sự đang chạy và lsofthay vào đó hãy kiểm tra để tìm tất cả các quy trình mở tập lệnh này?

Vâng, vâng, cách tiếp cận này thực sự không quá tệ:

if otherpids="$(lsof -t "$0" | grep -vFx "$$")"; then
  echo >&2 "Error: There are other processes that have this script open - most likely other copies of the script running.  Exiting to avoid conflicts."
  ps >&2 -fq "${otherpids//$'\n'/ }"
  exit 1
fi

Tất nhiên, nếu một bản sao của tập lệnh đang chạy, thì phiên bản mới sẽ khởi động tốt và bạn sẽ có hai bản sao đang chạy.

Hoặc nếu tập lệnh đang chạy được sửa đổi (ví dụ với Vim hoặc với a git checkout), thì phiên bản "mới" của tập lệnh sẽ khởi động không có vấn đề gì, vì cả Vim và git checkoutdẫn đến một tệp mới (một nút mới) thay cho người già.

Tuy nhiên, nếu kịch bản không bao giờ được sửa đổi và không bao giờ được sao chép, thì phiên bản này là khá tốt. Không có điều kiện chạy đua vì tệp tập lệnh đã được mở trước khi có thể đạt được kiểm tra.

Vẫn có thể có dương tính giả nếu một quá trình khác mở tệp tập lệnh, nhưng lưu ý rằng ngay cả khi nó mở để chỉnh sửa trong Vim, vim không thực sự giữ tệp tập lệnh mở nên sẽ không dẫn đến kết quả dương tính giả.

Nhưng hãy nhớ, không sử dụng phương pháp này nếu tập lệnh có thể được chỉnh sửa hoặc sao chép vì bạn sẽ nhận được âm bản giả, tức là nhiều trường hợp đang chạy cùng một lúc - vì vậy thực tế việc chỉnh sửa bằng Vim không mang lại kết quả dương tính giả không quan trọng để bạn Mặc dù vậy, tôi đề cập đến nó, bởi vì cách tiếp cận # 3 không cho kết quả dương tính giả (nghĩa là từ chối bắt đầu) nếu bạn mở tập lệnh với Vim.

Vậy phải làm sao?

Các câu trả lời hàng đầu bình chọn cho câu hỏi này đưa ra một cách tiếp cận tốt rắn.

Có lẽ bạn có thể viết một cái tốt hơn ... nhưng nếu bạn không hiểu tất cả các vấn đề và hãy cẩn thận với tất cả các cách tiếp cận ở trên, bạn không có khả năng viết một phương pháp khóa để tránh tất cả.



0

Đây là một cái gì đó đôi khi tôi thêm vào một máy chủ để dễ dàng xử lý các điều kiện cuộc đua cho bất kỳ công việc nào trên máy. Nó giống với bài của Tim Kennedy, nhưng theo cách này bạn có thể xử lý cuộc đua bằng cách chỉ thêm một hàng vào mỗi tập lệnh bash cần nó.

Đặt nội dung bên dưới trong ví dụ / opt / racechecker / racechecker:

ZPROGRAMNAME=$(readlink -f $0)
EZPROGRAMNAME=`echo $ZPROGRAMNAME | sed 's/\//_/g'`
EZMAIL="/usr/bin/mail"
EZCAT="/bin/cat"

if  [ -n "$EZPROGRAMNAME" ] ;then
        EZPIDFILE=/tmp/$EZPROGRAMNAME.pid
        if [ -e "$EZPIDFILE" ] ;then
                EZPID=$($EZCAT $EZPIDFILE)
                echo "" | $EZMAIL -s "$ZPROGRAMNAME already running with pid $EZPID"  alarms@someemail.com >>/dev/null
                exit -1
        fi
        echo $$ >> $EZPIDFILE
        function finish {
          rm  $EZPIDFILE
        }
        trap finish EXIT
fi

Đây là cách sử dụng nó. Lưu ý hàng sau shebang:

     #/bin/bash
     . /opt/racechecker/racechecker
     echo "script are running"
     sleep 120

Cách thức hoạt động là nó tìm ra tên tệp bashscript chính và tạo một tệp pidfile trong "/ tmp". Nó cũng thêm một người nghe vào tín hiệu kết thúc. Người nghe sẽ loại bỏ pidfile khi tập lệnh chính được hoàn thiện đúng.

Thay vào đó, nếu một pidfile tồn tại khi một cá thể được khởi chạy, thì câu lệnh if chứa mã bên trong câu lệnh if thứ hai sẽ được thực thi. Trong trường hợp này, tôi đã quyết định khởi động một thư báo động khi điều này xảy ra.

Nếu kịch bản gặp sự cố

Một bài tập nữa sẽ là xử lý sự cố. Lý tưởng nhất là loại bỏ pidfile ngay cả khi kịch bản chính gặp sự cố vì bất kỳ lý do nào, điều này không được thực hiện trong phiên bản của tôi ở trên. Điều đó có nghĩa là nếu tập lệnh gặp sự cố, pidfile sẽ phải được gỡ bỏ thủ công để khôi phục chức năng.

Trong trường hợp sự cố hệ thống

Đó là một ý tưởng tốt để lưu trữ pidfile / lockfile dưới ví dụ / tmp. Bằng cách này, các tập lệnh của bạn chắc chắn sẽ tiếp tục thực thi sau khi xảy ra sự cố hệ thống do các tệp pidfiles sẽ luôn bị xóa khi khởi động.


Không giống như ansatz của Tim Kennedy, kịch bản của bạn CÓ một điều kiện chủng tộc. Điều này là do việc bạn kiểm tra sự hiện diện của PIDFILE và việc tạo điều kiện của nó không được thực hiện trong một hoạt động nguyên tử.
maxschlepzig

+1 trên đó! Tôi sẽ xem xét điều này và sửa đổi kịch bản của tôi.
zigestardust

-2

Kiểm tra kịch bản của tôi ...

Bạn có thể yêu nó ....

[rambabu@Server01 ~]$ sh Prevent_cron-OR-Script_against_parallel_run.sh
Parallel RUN Enabled
Now running
Task completed in Parallel RUN...
[rambabu@Server01 ~]$ cat Prevent_cron-OR-Script_against_parallel_run.sh
#!/bin/bash
#Created by RambabuKella
#Date : 12-12-2013

#LOCK file name
Parallel_RUN="yes"
#Parallel_RUN="no"
PS_GREP=0
LOCK=/var/tmp/mylock_`whoami`_"$0"
#Checking for the process
PS_GREP=`ps -ef |grep "sh $0" |grep -v grep|wc -l`
if [ "$Parallel_RUN" == "no" ] ;then
echo "Parallel RUN Disabled"

 if [ -f $LOCK ] || [ $PS_GREP -gt 2   ] ;then
        echo -e "\nJob is already running OR LOCK file exists. "
        echo -e "\nDetail are : "
        ps -ef |grep  "$0" |grep -v grep
        cat "$LOCK"
  exit 6
 fi
echo -e "LOCK file \" $LOCK \" created on : `date +%F-%H-%M` ." &> $LOCK
# do some work
echo "Now running"
echo "Task completed on with single RUN ..."
#done

rm -v $LOCK 2>/dev/null
exit 0
else

echo "Parallel RUN Enabled"

# do some work
echo "Now running"
echo "Task completed in Parallel RUN..."
#done

exit 0
fi
echo "some thing wrong"
exit 2
[rambabu@Server01 ~]$

-3

Tôi đưa ra giải pháp sau đây, trong một kịch bản có tên 'flocktest'

#!/bin/bash
export LOGFILE=`basename $0`.logfile
logit () {
echo "$1" >>$LOGFILE
}
PROGPATH=$0
(
flock -x -n 257
(($?)) && logit "'$PROGPATH' is already running!" && exit 0
logit "'$PROGPATH', proc($$): sleeping 30 seconds"
sleep 30
)257<$PROGPATH
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.