বাশ স্ক্রিপ্টের কেবলমাত্র একটি উদাহরণ চলবে কীভাবে তা নিশ্চিত করবেন?


26

অতিরিক্ত সরঞ্জামগুলির প্রয়োজন হয় না এমন একটি সমাধান অগ্রাধিকার দেওয়া হবে।


একটি লক ফাইল সম্পর্কে কি?
মার্কো

@ মার্কো আমি এটি ব্যবহার করে এই এসও উত্তরটি পেয়েছি , তবে একটি মন্তব্যে যেমন বলা হয়েছে , এটি একটি রেসের শর্ত তৈরি করতে পারে
টোবিয়াস কেইনজলার


@ jw013 ধন্যবাদ! সুতরাং সম্ভবত এর মতো ln -s my.pid .lockকোনও কিছু লকটি দাবি করবে (তারপরে echo $$ > my.pid) এবং ব্যর্থতার কারণে এটি সংরক্ষিত পিআইডি .lockসত্যিই স্ক্রিপ্টের একটি সক্রিয় উদাহরণ কিনা
টোবিয়াস কেইনজলার

উত্তর:


18

প্রায় এনএসজি-র উত্তরের মতো: একটি লক ডিরেক্টরি ব্যবহার করুন । ডিরেক্টরি নির্মাণ লিনাক্স এবং ইউনিক্স এবং * বিএসডি এবং অন্যান্য অনেকগুলি ওএসের আওতায় পারমাণবিক।

if mkdir $LOCKDIR
then
    # Do important, exclusive stuff
    if rmdir $LOCKDIR
    then
        echo "Victory is mine"
    else
        echo "Could not remove lock dir" >&2
    fi
else
    # Handle error condition
    ...
fi

আপনি ডিবাগিংয়ের উদ্দেশ্যে লক ডিরেক্টরিতে একটি ফাইলের মধ্যে লকিং শের পিআইডি রাখতে পারেন, তবে ভাবনার ফাঁদে পড়বেন না যে লকিংয়ের প্রক্রিয়াটি এখনও কার্যকর হয় কিনা তা দেখতে আপনি সেই পিআইডি চেক করতে পারেন। প্রচুর বর্ণের পরিস্থিতি সেই পথে পড়ে lie


1
লকিংয়ের ঘটনাটি এখনও বেঁচে আছে কিনা তা পরীক্ষা করতে আমি সঞ্চিত পিআইডি ব্যবহার করে বিবেচনা করব। যাইহোক, এখানেmkdir এনএফএস-এ পারমাণবিক নয় এমন দাবি দাবি করা হয়েছে (যা আমার পক্ষে হয় না তবে আমার ধারণা অনুমান করা উচিত যে এটি যদি সত্য হয়)
টোবিয়াস কেইনজলার

হ্যাঁ, লকিংয়ের প্রক্রিয়াটি এখনও কার্যকর হয় কিনা তা দেখতে স্ট্রোকড পিআইডি ব্যবহার করুন তবে কোনও বার্তা লগ করা ছাড়া অন্য কিছু করার চেষ্টা করবেন না। সঞ্চিত পিড চেক করার কাজ, একটি নতুন পিআইডি ফাইল তৈরি করা ইত্যাদি দৌড়ের জন্য একটি বড় উইন্ডো ছেড়ে দেয়।
ব্রুস এডিগার

ঠিক আছে, যেমন ইহুনাথ বলেছেন , লকডিরটি সম্ভবত সম্ভবত /tmpএনএফএস ভাগ করে নেওয়া হয় না, তাই এটি ঠিক হওয়া উচিত।
টোবিয়াস কেইনজলার

আমি rm -rfলক ডিরেক্টরিটি সরানোর জন্য ব্যবহার করব । rmdirযদি কেউ (অগত্যা আপনি না) ডিরেক্টরিতে একটি ফাইল যুক্ত করতে সক্ষম হন তবে ব্যর্থ হবে।
চিপনার

18

ব্রুস এডিগার এর উত্তর যুক্ত করতে এবং এই উত্তর থেকে অনুপ্রাণিত হয়ে স্ক্রিপ্ট সমাপ্তির বিরুদ্ধে রক্ষা করতে আপনার পরিষ্কার-পরিচ্ছন্নতায় আরও স্মার্ট যুক্ত করতে হবে:

#Remove the lock directory
function cleanup {
    if rmdir $LOCKDIR; then
        echo "Finished"
    else
        echo "Failed to remove lock directory '$LOCKDIR'"
        exit 1
    fi
}

if mkdir $LOCKDIR; then
    #Ensure that if we "grabbed a lock", we release it
    #Works for SIGTERM and SIGINT(Ctrl-C)
    trap "cleanup" EXIT

    echo "Acquired lock, running"

    # Processing starts here
else
    echo "Could not create lock directory '$LOCKDIR'"
    exit 1
fi

বিকল্পভাবে if ! mkdir "$LOCKDIR"; then handle failure to lock and exit; fi trap and do processing after if-statement,।
কুসালানন্দ

6

এটি খুব সরল হতে পারে, আমি ভুল হলে দয়া করে আমাকে সংশোধন করুন। একটি সহজ psযথেষ্ট না?

#!/bin/bash 

me="$(basename "$0")";
running=$(ps h -C "$me" | grep -wv $$ | wc -l);
[[ $running > 1 ]] && exit;

# do stuff below this comment

1
সুন্দর এবং / বা উজ্জ্বল। :)
ভুতুড়ে

1
আমি এই শর্তটি এক সপ্তাহ ধরে ব্যবহার করেছি এবং 2 টি ক্ষেত্রে এটি নতুন প্রক্রিয়া শুরু হতে বাধা দেয় না। আমি সমস্যাটি কী তা বুঝতে পেরেছি - নতুন পিডটি পুরানোটির একটি স্ট্রাস্টিং এবং এতে লুকানো grep -v $$। বাস্তব উদাহরণ: পুরাতন - 14532, নতুন - 1453, পুরাতন - 28858, নতুন - 858.
নাকটিবলদা

আমি পরিবর্তন করে এটি সংশোধন grep -v $$করতেgrep -v "^${$} "
Naktibalda

@ শক্তিবল্ডা ভাল ক্যাচ, ধন্যবাদ! আপনি এটি grep -wv "^$$"সম্পাদনা করে (সম্পাদনা দেখুন ) ও ঠিক করতে পারেন।
টেরডন

আপডেটের জন্য ধন্যবাদ। আমার প্যাটার্ন মাঝেমধ্যে ব্যর্থ হয়েছে কারণ ছোট পিডগুলি ফাঁকা জায়গা দিয়ে রেখেছিল।
নাকটিবলদা

4

আমি মার্কো দ্বারা উল্লিখিত হিসাবে একটি লক ফাইল ব্যবহার করব

#!/bin/bash

# Exit if /tmp/lock.file exists
[ -f /tmp/lock.file ] && exit

# Create lock file, sleep 1 sec and verify lock
echo $$ > /tmp/lock.file
sleep 1
[ "x$(cat /tmp/lock.file)" == "x"$$ ] || exit

# Do stuff
sleep 60

# Remove lock file
rm /tmp/lock.file

1
(আমি মনে করি আপনি লক ফাইলটি তৈরি করতে ভুলে গেছেন) জাতি অবস্থার কী হবে ?
টোবিয়াস কেইনজলার

অপস :) হ্যাঁ, জাতিগত অবস্থা আমার উদাহরণে একটি সমস্যা, আমি সাধারণত ঘন্টা বা দৈনিক ক্রোন জব লিখি এবং বর্ণের অবস্থা বিরল।
এনএসজি

তারা আমার ক্ষেত্রে প্রাসঙ্গিক হওয়া উচিত নয়, তবে এটি এমন কিছু বিষয় মনে রাখা উচিত। সম্ভবত ব্যবহার lsof $0খারাপ হয় না?
টোবিয়াস কেইনজলার

আপনি $$লক ফাইলটিতে লিখে রেসের অবস্থা হ্রাস করতে পারেন । তারপরে sleepএকটি স্বল্প বিরতির জন্য এবং এটি আবার পড়ুন। যদি পিআইডি এখনও আপনার হয়, আপনি সফলভাবে লকটি অর্জন করেছেন। একেবারে কোনও অতিরিক্ত সরঞ্জামের প্রয়োজন।
manatwork

1
আমি কখনই এই উদ্দেশ্যে লসফ ব্যবহার করি নি, এটি কাজ করা উচিত। নোট করুন যে lsof আমার সিস্টেমে সত্যই ধীর গতিতে রয়েছে (1-2 সেকেন্ড) এবং সম্ভবত রেসের অবস্থার জন্য অনেক সময় রয়েছে।
এনএসজি

3

আপনি যদি নিশ্চিত করতে চান যে আপনার স্ক্রিপ্টের কেবলমাত্র একটি উদাহরণ চলছে তবে একবার দেখুন:

আপনার স্ক্রিপ্ট লক করুন (সমান্তরাল রান বিরুদ্ধে)

অন্যথায় আপনি চেক psবা অনুরোধ করতে পারেন lsof <full-path-of-your-script>, যেহেতু আমি তাদের অতিরিক্ত সরঞ্জামগুলি বলব না।


পরিপূরক :

আসলে আমি এটি এইভাবে করার কথা ভেবেছিলাম:

for LINE in `lsof -c <your_script> -F p`; do 
    if [ $$ -gt ${LINE#?} ] ; then
        echo "'$0' is already running" 1>&2
        exit 1;
    fi
done

এটি নিশ্চিত করে যে আপনি সর্বনিম্ন সহ প্রক্রিয়াটি একই সাথে pidচলতে থাকবে এমনকি আপনি <your_script>একসাথে বেশ কয়েকটি উদাহরণ কাঁটাচামচ করে-চালিয়ে যান ।


1
লিঙ্কটির জন্য ধন্যবাদ, তবে আপনি কি আপনার উত্তরের প্রয়োজনীয় অংশগুলি অন্তর্ভুক্ত করতে পারেন? লিঙ্ক পচা রোধে এটি এসই-তে সাধারণ নীতি ... তবে এর মতো কিছু [[(lsof $0 | wc -l) > 2]] && exitআসলে আসলে যথেষ্ট, বা এটিও রেসের শর্তে প্রবণ?
টোবিয়াস কেইনজলার

আপনি ঠিক বলেছেন আমার উত্তরের অপরিহার্য অংশটি অনুপস্থিত ছিল এবং কেবল পোস্টিং লিঙ্কগুলি বেশ লম্পট। আমি উত্তরে আমার নিজের পরামর্শ যুক্ত করেছি।
ব্যবহারকারী 1146332

3

বাশ স্ক্রিপ্টের একক উদাহরণ চলে তা নিশ্চিত করার জন্য অন্য একটি উপায়:

#!/bin/bash

# Check if another instance of script is running
pidof -o %PPID -x $0 >/dev/null && echo "ERROR: Script $0 already running" && exit 1

...

pidof -o %PPID -x $0 ইতিমধ্যে চলমান থাকলে বিদ্যমান স্ক্রিপ্টের পিআইডি পেয়ে যায় বা অন্য কোনও স্ক্রিপ্ট না চললে ত্রুটি কোড 1 সহ প্রস্থান করে


3

যদিও আপনি অতিরিক্ত সরঞ্জাম ছাড়াই সমাধান চেয়েছিলেন, এটি আমার প্রিয় উপায় flock:

#!/bin/sh

[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :

echo "servus!"
sleep 10

এটি এর উদাহরণ বিভাগ থেকে আসে man flock, যা আরও ব্যাখ্যা করে:

এটি শেল স্ক্রিপ্টগুলির জন্য দরকারী বয়লারপ্লেট কোড। আপনি যে শেল স্ক্রিপ্টটি লক করতে চান তার শীর্ষে রাখুন এবং এটি স্বয়ংক্রিয়ভাবে প্রথম দৌলে নিজেকে লক হয়ে যাবে। যদি env var $ FLOCKER চালিত শেল স্ক্রিপ্টে সেট না করা থাকে তবে সঠিকভাবে যুক্তি দিয়ে নিজেকে পুনরায় চালিত করার আগে ঝাঁকটি নির্বাহ করুন এবং একচেটিয়া অ-ব্লকিং লক (স্ক্রিপ্টটিকে লক ফাইল হিসাবে ব্যবহার করুন) ধরুন। এটি FLOCKER env varকে সঠিক মান হিসাবে সেট করে যাতে এটি আবার চালিত হয় না।

বিবেচনা করার বিষয়গুলি:

  • প্রয়োজনীয় flock, উদাহরণস্বরূপ স্ক্রিপ্টটি একটি ত্রুটিযুক্ত সাথে এটি শেষ না হলে এটি শেষ করে
  • কোনও অতিরিক্ত লক ফাইলের প্রয়োজন
  • স্ক্রিপ্টটি এনএফএসে থাকলে কাজ করতে পারে না ( /server/66919/file-locks-on-an-nfs দেখুন )

Https://stackoverflow.com/questions/185451/quick-and-dirty-way-to-ensure-only-one-instance-of-a-shell-script-is-running-at এও দেখুন ।


1

এটি আনসেলমোর উত্তরের একটি পরিবর্তিত সংস্করণ । ধারণাটি হ'ল বাশ স্ক্রিপ্টটি নিজেই একটি পঠনযোগ্য ফাইল বর্ণনাকারী তৈরি করা এবং flockলকটি পরিচালনা করতে ব্যবহার করা।

SCRIPT=`realpath $0`     # get absolute path to the script itself
exec 6< "$SCRIPT"        # open bash script using file descriptor 6
flock -n 6 || { echo "ERROR: script is already running" && exit 1; }   # lock file descriptor 6 OR show error message if script is already running

echo "Run your single instance code here"

অন্যান্য সমস্ত উত্তরের মূল পার্থক্য হ'ল এই কোডটি ফাইল সিস্টেমকে সংশোধন করে না, খুব কম পায়ের ছাপ ব্যবহার করে এবং কোনও স্ক্রিনআপের প্রয়োজন হয় না কারণ ফাইল স্ক্রিপ্টটি প্রস্থান স্থিতি ছাড়াই স্ক্রিপ্ট শেষ হওয়ার সাথে সাথেই বন্ধ হয়ে যায়। সুতরাং স্ক্রিপ্টটি ব্যর্থ হয় বা সফল হয় তা বিবেচ্য নয়।


আপনার কাছে সবসময় সমস্ত শেল পরিবর্তনশীল রেফারেন্স উদ্ধৃত করা উচিত যদি না আপনার কাছে না করার কোনও ভাল কারণ না থাকে এবং আপনি নিশ্চিত যে আপনি কী করছেন তা আপনি নিশ্চিত । সুতরাং আপনি করা উচিত exec 6< "$SCRIPT"
স্কট

@ স্কট আমি আপনার পরামর্শ অনুসারে কোড পরিবর্তন করেছি। অনেক ধন্যবাদ.
জন দো

1

আমি আমার স্ক্রিপ্টটি সত্যই একক দৃষ্টান্তে চলছে তা যাচাই করতে cksum ব্যবহার করছি , এমনকি আমি ফাইলের নাম এবং ফাইলের পথও পরিবর্তন করি

আমি ট্র্যাপ ও লক ফাইলটি ব্যবহার করছি না, কারণ আমার সার্ভারটি হঠাৎ ডাউন হয়ে গেলে সার্ভার উপরে উঠে যাওয়ার পরে আমাকে ম্যানুয়ালি লক ফাইলটি সরিয়ে ফেলতে হবে।

দ্রষ্টব্য: #! / বিন / বাশ প্রথম লাইনে গ্রেপ পিএসের জন্য প্রয়োজনীয়

#!/bin/bash

checkinstance(){
   nprog=0
   mysum=$(cksum $0|awk '{print $1}')
   for i in `ps -ef |grep /bin/bash|awk '{print $2}'`;do 
        proc=$(ls -lha /proc/$i/exe 2> /dev/null|grep bash) 
        if [[ $? -eq 0 ]];then 
           cmd=$(strings /proc/$i/cmdline|grep -v bash)
                if [[ $? -eq 0 ]];then 
                   fsum=$(cksum /proc/$i/cwd/$cmd|awk '{print $1}')
                   if [[ $mysum -eq $fsum ]];then
                        nprog=$(($nprog+1))
                   fi
                fi
        fi
   done

   if [[ $nprog -gt 1 ]];then
        echo $0 is already running.
        exit
   fi
}

checkinstance 

#--- run your script bellow 

echo pass
while true;do sleep 1000;done

অথবা আপনি নিজের স্ক্রিপ্টের অভ্যন্তরে cksum হার্ডকোড করতে পারেন, তাই যদি আপনি ফাইলের নাম, পথ বা আপনার স্ক্রিপ্টের বিষয়বস্তু পরিবর্তন করতে চান তবে আপনার আর উদ্বেগ হওয়ার দরকার নেই

#!/bin/bash

mysum=1174212411

checkinstance(){
   nprog=0
   for i in `ps -ef |grep /bin/bash|awk '{print $2}'`;do 
        proc=$(ls -lha /proc/$i/exe 2> /dev/null|grep bash) 
        if [[ $? -eq 0 ]];then 
           cmd=$(strings /proc/$i/cmdline|grep -v bash)
                if [[ $? -eq 0 ]];then 
                   fsum=$(grep mysum /proc/$i/cwd/$cmd|head -1|awk -F= '{print $2}')
                   if [[ $mysum -eq $fsum ]];then
                        nprog=$(($nprog+1))
                   fi
                fi
        fi
   done

   if [[ $nprog -gt 1 ]];then
        echo $0 is already running.
        exit
   fi
}

checkinstance

#--- run your script bellow

echo pass
while true;do sleep 1000;done

1
চেকসামটি কীভাবে হার্ডকোডিং করা ভাল ধারণা তা দয়া করে ব্যাখ্যা করুন।
স্কট

হার্ডকডিং চেকসাম নয়, এটি আপনার স্ক্রিপ্টের একমাত্র পরিচয় কী তৈরি করবে, যখন অন্য একটি দৃষ্টান্ত চলবে, এটি অন্য শেল স্ক্রিপ্ট প্রক্রিয়াটি পরীক্ষা করবে এবং প্রথমে ফাইলটিকে বিড়াল করবে, যদি আপনার পরিচয় কী সেই ফাইলটিতে থাকে, সুতরাং এর অর্থ আপনার ইতিমধ্যে ইতিমধ্যে চলছে।
আরপুত্র

ঠিক আছে; এটি ব্যাখ্যা করতে দয়া করে আপনার উত্তরটি সম্পাদনা করুন। এবং, ভবিষ্যতে, কোড না পোস্টে একাধিক 30-লাইন দীর্ঘ ব্লক দয়া করে যে, তারা মত চেহারা চলেছি (প্রায়) ছাড়া অভিন্ন বলার অপেক্ষা রাখে না এবং ব্যাখ্যা কিভাবে তারা আলাদা। এবং "আপনি আপনার স্ক্রিপ্টের অভ্যন্তরে হার্ডকডড [sic] সিক্সাম করতে পারেন" এর মতো কথা বলবেন না, এবং ভেরিয়েবলের নাম ব্যবহার করা চালিয়ে যান না mysumএবং fsumযখন আপনি আর কোনও চেকসামের কথা বলছেন না।
স্কট

আকর্ষণীয় দেখাচ্ছে, ধন্যবাদ! আর unix.stackexchange করার :) স্বাগত জানাই
Tobias Kienzler


0

আমার কোড আপনাকে

#!/bin/bash

script_file="$(/bin/readlink -f $0)"
lock_file=${script_file////_}

function executing {
  echo "'${script_file}' already executing"
  exit 1
}

(
  flock -n 9 || executing

  sleep 10

) 9> /var/lock/${lock_file}

ভিত্তিক man flock, কেবল উন্নতি:

  • স্ক্রিপ্টের পুরো নামের উপর ভিত্তি করে লক ফাইলের নাম
  • বার্তা executing

আমি এখানে যেখানে রেখেছি sleep 10আপনি সমস্ত মূল স্ক্রিপ্ট রাখতে পারেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.