كيفية التعامل مع زمن استجابة NFS في البرامج النصية لـ Shell

StackOverflow https://stackoverflow.com/questions/1078044

  •  21-08-2019
  •  | 
  •  

سؤال

أنا أكتب البرامج النصية Shell حيث تتم كتابة بعض الأشياء بانتظام إلى ملف ، وبعد ذلك يتم تنفيذ تطبيق يقرأ هذا الملف.أجد أنه من خلال شركتنا يختلف زمن استجابة الشبكة بشكل كبير، وهذا أمر بسيط sleep 2 على سبيل المثال لن تكون قوية بما فيه الكفاية.

حاولت كتابة حلقة مهلة (قابلة للتكوين) مثل هذا:

waitLoop()
{
   local timeout=$1
   local test="$2"

   if ! $test
   then
      local counter=0
      while ! $test && [ $counter -lt $timeout ]
      do
         sleep 1
         ((counter++))
      done

      if ! $test
      then
         exit 1
      fi
   fi
}

هذا يعمل ل test="[ -e $somefilename ]".ومع ذلك، اختبار الوجود ليس كافيًا، أحتاج أحيانًا إلى اختبار ما إذا كان قد تم كتابة سلسلة معينة في الملف.حاولتtest="grep -sq \"^sometext$\" $somefilename", ، ولكن هذا لم ينجح.هل يمكن لأحد أن يقول لي لماذا؟

هل هناك خيارات أخرى أقل تفصيلاً لإجراء مثل هذا الاختبار؟

هل كانت مفيدة؟

المحلول

ويمكنك تعيين متغير الاختبار الخاصة بك بهذه الطريقة:

test=$(grep -sq "^sometext$" $somefilename)

والسبب grep الخاص بك لا يعمل هو أن يقتبس من الصعب حقا أن يمر في الحجج. سوف تحتاج إلى استخدام eval:

if ! eval $test

نصائح أخرى

أريد أن أقول ال طريقة التحقق من وجود سلسلة في ملف نصي هي grep.

ما هي مشكلتك بالضبط معها؟

يمكنك أيضًا ضبط معلمات تثبيت NFS للتخلص من المشكلة الجذرية.قد تساعد المزامنة أيضًا.راجع مستندات NFS.

إذا كنت ترغب في استخدام waitLoop في "لو"، قد ترغب في تغيير "الخروج" إلى "العودة"، وبالتالي فإن بقية السيناريو يمكن التعامل مع الوضع الخطأ (ليس هناك حتى رسالة ل المستخدم حول ما فشلت قبل أن يموت النص على خلاف ذلك).

والمسألة الأخرى يستخدم "اختبار $" لعقد أمر يعني أنك لا تحصل على التوسع قذيفة عند تنفيذ في الواقع، مجرد تقييم. حتى إذا كنت أقول اختبار = "البقرى \" فو \ "\" شريط الباز \ ""، بدلا من النظر للفو سلسلة من ثلاثة أحرف في الملف مع شريط اسم سبعة الطابع الباز، وأنها سوف نبحث عن سلسلة شار خمسة "فو" في ملف تسعة شار "شريط باز".

وهكذا يمكنك إما قررت أنك لا تحتاج إلى السحر قذيفة، ووضع اختبار = 'البقرى -sq ^ sometext $ somefilename، أو يمكنك الحصول على وعاء للتعامل مع نقلا صراحة مع شيء من هذا القبيل:

if /bin/sh -c "$test"
then
   ...

وحاول استخدام الوقت ملف تعديل للكشف عند كتابة من دون فتحه. شيء من هذا القبيل

old_mtime=`stat --format="%Z" file`
# Write to file.
new_mtime=$old_mtime
while [[ "$old_mtime" -eq "$new_mtime" ]]; do 
  sleep 2;
  new_mtime=`stat --format="%Z" file`
done

وهذا لن ينجح، ولكن إذا حاول عمليات متعددة للوصول إلى ملف في نفس الوقت.

ولقد كان نفس المشكلة بالضبط. كنت نهجا مماثلا لالانتظار المهلة التي قمت بتضمين في OP الخاص بك؛ ومع ذلك، وشملت أيضا فحص حجم الملف. I إعادة بلدي الموقت المهلة إذا كان الملف قد زادت في حجم منذ آخر تم إيداعه. الملفات أنا أكتب يمكن أن يكون عدد قليل من أزعج، بحيث يستغرق بعض الوقت لكتابة عبر NFS.

وهذا قد يكون مبالغة لحالة معينة، ولكن كان أيضا بلدي عملية الكتابة حساب تجزئة الملف بعد أن فعلت ذلك كتابة. كنت md5، ولكن شيئا من هذا القبيل CRC32 العمل أيضا. تم بث هذه التجزئة من الكاتب إلى (متعددة) القراء، والقارئ ينتظر حتى أ) حجم الملف يتوقف زيادة وب) (المحسوبة حديثا) تجزئة الملف يطابق التجزئة التي بعث بها الكاتب.

لدينا مشكلة مشابهة، ولكن لأسباب مختلفة. نحن نقرأ ملف الصورة، التي يتم إرسالها إلى خادم SFTP. الجهاز تشغيل البرنامج النصي ليست خادم SFTP.

وماذا فعلت تم إعداده في كرون (على الرغم من حلقة مع النوم ستعمل أيضا) للقيام cksum من الملف. عندما يطابق cksum القديم cksum الحالي (لم يتغير ملف لمبلغ محدد من الزمن) ونحن نعلم أن يكتب كاملة، ونقل الملف.

وفقط لمزيد من الأمان، ونحن لم الكتابة فوق الملف المحلي قبل اتخاذ النسخ الاحتياطي، ونقل الوحيد على الإطلاق عندما الملف البعيد اثنين cksums على التوالي التي تطابق، والتي cksum لا يطابق ملف محلي.

إذا كنت بحاجة إلى أمثلة التعليمات البرمجية، وأنا واثق من أنني يمكن حفر لهم.

وقذيفة ويقطع المسند إلى كلمات. الاستيلاء على كل شيء مع $@ كما في التعليمات البرمجية أدناه:

#! /bin/bash

waitFor()
{
  local tries=$1
  shift
  local predicate="$@"

  while [ $tries -ge 1 ]; do
    (( tries-- ))

    if $predicate >/dev/null 2>&1; then
      return
    else
      [ $tries -gt 0 ] && sleep 1
    fi
  done

  exit 1
}

pred='[ -e /etc/passwd ]'
waitFor 5 $pred
echo "$pred satisfied"

rm -f /tmp/baz
(sleep 2; echo blahblah >>/tmp/baz) &
(sleep 4; echo hasfoo   >>/tmp/baz) &

pred='grep ^hasfoo /tmp/baz'
waitFor 5 $pred
echo "$pred satisfied"

وإخراج:

$ ./waitngo 
[ -e /etc/passwd ] satisfied
grep ^hasfoo /tmp/baz satisfied

وسيئة للغاية في نسخة مطبوعة على الآلة الكاتبة ليست مثيرة للاهتمام كما مشاهدته في الوقت الحقيقي.

طيب ... هذا هو أحمق قليلا ...

إذا كان لديك السيطرة على الملف: كنت قد تكون قادرة على خلق 'إخراج مسمى' هنا. حتى (اعتمادا على الكيفية التي يعمل بها برنامج الكتابة) يمكنك مراقبة الملف بطريقة متزامنة.

وفي أبسط صورها:

وإنشاء إخراج مسمى:

mkfifo file.txt

وإعداد المتلقي مزامنة:

while :
do
    process.sh < file.txt
end

وإنشاء مرسل الاختبار:

echo "Hello There" > file.txt

وو"process.sh" هو المكان الذي يذهب المنطق الخاص: هذا سيمنع حتى المرسل تمت كتابة انتاجها. من الناحية النظرية فإن برنامج الكاتب لا يحتاج modifiying ....

تحذير: إذا كان المتلقي لا يعمل لسبب ما، قد ينتهي بك الأمر حجب المرسل

ولست متأكدا أنه يناسب الاحتياجات الخاصة بك هنا، ولكن قد يكون من المفيد النظر في.

وأو لتجنب متزامنة، في محاولة "lsof؟

http://en.wikipedia.org/wiki/Lsof

وعلى افتراض أن كنت ترغب فقط في قراءة الملف من أي شيء آخر عندما يكتب عليه (أي، انتهاء عملية الكتابة؟) - هل يمكن أن تحقق ما إذا كان أي شيء آخر له مقبض الملف لأنه

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top