একটি স্ট্রিং পাওয়া পর্যন্ত একটি ফাইল নিরীক্ষণ


49

আমি tail -f ব্যবহার করছি একটি লগ ফাইল নিরীক্ষণ করতে যা সক্রিয়ভাবে লিখিত হচ্ছে। যখন একটি নির্দিষ্ট স্ট্রিং লগ ফাইলে লেখা হয়, আমি পর্যবেক্ষণ বন্ধ করতে চাই এবং আমার বাকি স্ক্রিপ্টটি চালিয়ে যেতে চাই।

বর্তমানে আমি ব্যবহার করছি:

tail -f logfile.log | grep -m 1 "Server Started"

যখন স্ট্রিং পাওয়া যায়, grep প্রত্যাশিত হিসাবে প্রস্থান করে, তবে লেজ কমান্ডটিও প্রস্থান করার জন্য আমাকে একটি উপায় খুঁজে বের করতে হবে যাতে স্ক্রিপ্টটি চালিয়ে যেতে পারে।


আমি মূল পোস্টার চলমান অপারেটিং সিস্টেম কি ভাবছি। লিনাক্স আরএইচএইচ 5 সিস্টেমের উপর, আমি দেখে অবাক হলাম যে জিপি কমান্ডটি ম্যাচটি খুঁজে বের হয়ে বেরিয়ে গেলে লেজ কমান্ডটি সহজেই মারা যায়।
ZaSter

3
@ জাস্টার: দ্য tail পরের লাইনে শুধুমাত্র মরে। এটা চেষ্টা কর: date > log; tail -f log | grep -m 1 trigger এবং তারপর অন্য শেল মধ্যে: echo trigger >> log এবং আপনি আউটপুট দেখতে হবে trigger প্রথম শেল, কিন্তু কমান্ড কোন বাতিল। তারপর চেষ্টা করুন: date >> log দ্বিতীয় শেলের মধ্যে এবং প্রথম শেলের কমান্ডটি শেষ হবে। কিন্তু কখনও কখনও এই খুব দেরী হয়; যত তাড়াতাড়ি ট্রিগার লাইন হাজির হয় ততক্ষণ আমরা ট্রিগার লাইনের পরে লাইনটি শেষ করতে চাই না।
Alfe

এটি একটি চমৎকার ব্যাখ্যা এবং উদাহরণ, @ আলফ।
ZaSter

1
মার্জিত এক লাইন শক্তসমর্থ সমাধান হয় ব্যবহার tail + + grep -q 00prometheus এর উত্তর মত
Trevor Boyd Smith

উত্তর:


24

একটি সহজ POSIX এক-মাছ ধরার নৌকা

এখানে একটি সহজ এক-মাছ ধরার নৌকা। এটি ব্যাশ-নির্দিষ্ট বা অ-পসিক্স ট্রিকস বা এমনকি একটি নামযুক্ত পাইপের প্রয়োজন নেই। আপনি সত্যিই প্রয়োজন সব বিনষ্ট decouple হয় tail থেকে grep। যে ভাবে, একবার grep শেষ, স্ক্রিপ্ট এমনকি যদি অবিরত করতে পারেন tail এখনো শেষ না। তাই এই সহজ পদ্ধতি আপনি সেখানে পাবেন:

( tail -f -n0 logfile.log & ) | grep -q "Server Started"

grep এটি স্ট্রিং খুঁজে পাওয়া পর্যন্ত ব্লক করা হবে, যেখানে এটি প্রস্থান করা হবে। তৈরি করে tail এটির নিজস্ব উপ-শেল থেকে চালান, আমরা এটি পটভূমিতে রাখতে পারি যাতে এটি স্বাধীনভাবে চলতে পারে। এদিকে, প্রধান শেল যত তাড়াতাড়ি স্ক্রিপ্ট নির্বাহ চালিয়ে যেতে বিনামূল্যে grep প্রস্থান করে। tail পরের লাইনটি লগফাইলে লিখিত না হওয়া পর্যন্ত তার সাব-শেলে থাকবে, এবং তারপর প্রস্থান করুন (সম্ভবত মূল স্ক্রিপ্ট বন্ধ হওয়ার পরেও)। মূল বিন্দু যে পাইপলাইন আর অপেক্ষা করে tail বিনষ্ট করা, তাই পাইপলাইন যত তাড়াতাড়ি প্রস্থান grep প্রস্থান করে।

কিছু ছোটখাট tweaks:

  • বিকল্প -00 থেকে tail লগফিলের পূর্বে স্ট্রিং বিদ্যমান থাকলে লগফিলের বর্তমান শেষ লাইন থেকে এটি পড়তে শুরু করে।
  • আপনি দিতে দিতে পারেন tail -F পরিবর্তে -ফ। এটা POSIX নয়, কিন্তু এটি অনুমতি দেয় tail অপেক্ষা করার সময় লগ ঘোরানো হলেও কাজ করতে।
  • বিকল্প -q পরিবর্তে -m1 তোলে grep প্রথম ঘটনা পরে ছেড়ে, কিন্তু ট্রিগার লাইন প্রিন্টিং ছাড়া। এছাড়াও এটি POSIX, যা -এম 1 হয় না।

2
এই পদ্ধতি ছেড়ে চলে যাবে tail কখনও জন্য পটভূমিতে চলমান। আপনি কিভাবে ক্যাপচার হবে tail পিআইডি ব্যাকগ্রাউন্ড সাব শেলের মধ্যে এবং এটি প্রধান শেল প্রকাশ? আমি সংযুক্ত সমস্ত অধিবেশন হত্যা করে শুধুমাত্র উপ-ঐচ্ছিক workaround সঙ্গে আসতে পারেন tail প্রক্রিয়া, ব্যবহার করে pkill -s 0 tail
Rick van der Zwet

সর্বাধিক ব্যবহারের ক্ষেত্রে এটি একটি সমস্যা হতে পারে না। আপনি প্রথম স্থানে এটি করছেন কারন আপনি লগ ফাইলে আরো লাইন লিখতে প্রত্যাশা করছেন। tail যত তাড়াতাড়ি এটি একটি ভাঙ্গা পাইপ লিখতে চেষ্টা করে শেষ হবে। পাইপ যত তাড়াতাড়ি বিরতি হবে grep সম্পন্ন হয়েছে, তাই একবার grep সম্পন্ন হয়েছে, tail লগ ফাইল এটি একটি লাইন পায় পর শেষ হবে।
00prometheus

যখন আমি এই সমাধান ব্যবহার করতাম না পটভূমি tail -f
Trevor Boyd Smith

2
@ ট্রেভর বয়েড স্মিথ, হ্যাঁ, এটি বেশিরভাগ ক্ষেত্রে কাজ করে, কিন্তু OP সমস্যাটি ছিল যে grep tail quits পর্যন্ত সম্পূর্ণ হবে না এবং লগ ফাইলটিতে অন্য কোনও লাইন উপস্থিত না হওয়া পর্যন্ত লেখনটি ছেড়ে দেওয়া হবে না। পরে grep ছেড়ে চলে গেছে (যখন লেপ grep শেষ দ্বারা ভাঙ্গা পাইপলাইন খাওয়ানোর চেষ্টা করে)। সুতরাং আপনি ব্যাকগ্রাউন্ড লেজ না থাকলে, grep ক্যাচে থাকা লাইনের তুলনায় লগ ফাইলটিতে অতিরিক্ত লাইন হাজির না হওয়া পর্যন্ত আপনার স্ক্রিপ্ট কার্যকর থাকবে না।
00prometheus

Re "অন্য লাইনটি [প্রয়োজনীয় স্ট্রিং প্যাটার্ন] পরে প্রদর্শিত না হওয়া পর্যন্ত ট্রিলটি ছাড়বে না": এটি খুব কমই এবং আমি সম্পূর্ণরূপে এটি মিস করেছি। আমি লক্ষ্য করিনি কারণ আমি যে প্যাটার্নটি খুঁজছিলাম তা মাঝখানে ছিল এবং এটি সব দ্রুত ছাপা হয়েছিল। (আবার আপনি বর্ণিত আচরণ খুব সূক্ষ্ম)
Trevor Boyd Smith

54

গ্রহণযোগ্য উত্তর আমার জন্য কাজ করছে না, প্লাস এটি বিভ্রান্তিকর এবং এটি লগ ফাইল পরিবর্তন করে।

আমি এই ভালো কিছু ব্যবহার করছি:

tail -f logfile.log | while read LOGLINE
do
   [[ "${LOGLINE}" == *"Server Started"* ]] && pkill -P $$ tail
done

লগ লাইন প্যাটার্ন মিললে, হত্যা tail এই স্ক্রিপ্ট দ্বারা শুরু।

নোট: আপনি পর্দায় আউটপুট দেখতে চান, হয় | tee /dev/tty অথবা লুপ পরীক্ষা করার আগে লাইন প্রতিধ্বনি।


2
এই কাজ, কিন্তু pkill POSIX দ্বারা নির্দিষ্ট করা হয় না এবং সর্বত্র পাওয়া যায় না।
Richard Hansen

2
আপনি একটি সময় লুপ প্রয়োজন হবে না। -G বিকল্প সঙ্গে ঘড়ি ব্যবহার করুন এবং আপনি নিজেকে কদর্য pkill কমান্ড পরিত্যাগ করতে পারেন।
l1zard

@ l1zard আপনি কি এটিকে মাংস করতে পারেন? একটি নির্দিষ্ট লাইন দেখানো পর্যন্ত আপনি একটি লগ ফাইলের লেজ কিভাবে দেখতে হবে? (কম গুরুত্বপূর্ণ, কিন্তু যখন আমি watch-g যুক্ত ছিল তখনও কৌতুহলী নই; আমার কাছে বিকল্পটি দিয়ে একটি নতুন ডেবিয়ান সার্ভার রয়েছে এবং এটি ছাড়া আর একটি পুরানো RHEL- ভিত্তিক একটি)।
Rob Whelan

এটা আমার কাছে স্পষ্ট নয় কেন এখানে লেজও দরকার। যতক্ষণ আমি এই সঠিক বুঝি, একটি লগ ফাইলের একটি নির্দিষ্ট কীওয়ার্ড উপস্থিত হলে ব্যবহারকারী একটি নির্দিষ্ট কমান্ডটি চালাতে চায়। ঘড়ি ব্যবহার করে নীচের কমান্ড এই খুব কাজ করে।
l1zard

বেশ না - এটি একটি প্রদত্ত স্ট্রিং যখন চেক করা হয় যোগ লগ ফাইল। Tomcat বা JBoss সম্পূর্ণরূপে শুরু হয় যখন আমি চেক করার জন্য এই ব্যবহার; তারা লিখুন "সার্ভার শুরু" (বা অনুরূপ) প্রতিটি সময় ঘটে।
Rob Whelan

14

পেতে কয়েক উপায় আছে tail প্রস্থান করা:

দরিদ্র দৃষ্টিভঙ্গি: ফোর্স tail অন্য লাইন লিখতে

আপনি জোর করতে পারেন tail অবিলম্বে আউটপুট আরেকটি লাইন লিখতে grep একটি ম্যাচ পাওয়া গেছে এবং exited। এই কারণ হবে tail একটি পেতে SIGPIPE, এটি প্রস্থান করার কারণ। এটি করার একটি উপায় হল নজরদারি করা ফাইলটি সংশোধন করা tail পরে grep প্রস্থান করে।

এখানে কিছু উদাহরণ কোড রয়েছে:

tail -f logfile.log | grep -m 1 "Server Started" | { cat; echo >>logfile.log; }

এই উদাহরণে, cat পর্যন্ত প্রস্থান করা হবে না grep তার stdout বন্ধ হয়েছে, তাই tail আগে পাইপ লিখতে সক্ষম হতে পারে না grep তার stdin বন্ধ করার সুযোগ আছে। cat স্ট্যান্ডার্ড আউটপুট প্রচার করতে ব্যবহৃত হয় grep অপরিবর্তিত।

এই পদ্ধতির তুলনামূলকভাবে সহজ, কিন্তু বিভিন্ন downsides আছে:

  • যদি grep stdin বন্ধ করার আগে stdout বন্ধ, সবসময় একটি জাতি অবস্থা হতে হবে: grep stdout বন্ধ, triggering cat প্রস্থান করার জন্য, ট্রিগার echo, ট্রিগার tail একটি লাইন আউটপুট। এই লাইন পাঠানো হয় grep আগে grep stdin বন্ধ করার সুযোগ আছে, tail পাবেন না SIGPIPE এটি অন্য লাইন লিখে না হওয়া পর্যন্ত।
  • এটি লগ ফাইল অ্যাক্সেস লিখতে হবে।
  • আপনি লগ ফাইল সংশোধন সঙ্গে ঠিক আছে।
  • আপনি যদি অন্য প্রক্রিয়া হিসাবে একই সময়ে লিখতে চান তবে আপনি লগ ফাইলটি দূষিত করতে পারেন (লেখার সাথে একত্রিত হতে পারে, একটি লগইন বার্তা মাঝখানে একটি নতুন লাইন দেখাতে পারে)।
  • এই পদ্ধতির নির্দিষ্ট tail এটা অন্যান্য প্রোগ্রামের সাথে কাজ করবে না।
  • তৃতীয় পাইপলাইন পর্যায়টি দ্বিতীয় পাইপলাইনে পর্যায়টির রিটার্ন কোড অ্যাক্সেস করা কঠিন করে তোলে (যদি না আপনি একটি POSIX এক্সটেনশন ব্যবহার করেন যেমন bash এর PIPESTATUS অ্যারে)। কারণ এই ক্ষেত্রে একটি বড় চুক্তি নয় grep সর্বদা 0 ফিরে আসবে, তবে সাধারণভাবে মাঝারি পর্যায়ে ভিন্ন কমান্ডের প্রতিস্থাপিত হতে পারে যার রিটার্ন কোডটি আপনি যত্নশীল (উদাহরণস্বরূপ, "সার্ভার শুরু হওয়া" সনাক্ত হওয়ার পরে 0 টি ফেরৎ এমন কিছু, 1 "সার্ভারটি শুরুতে ব্যর্থ হয়েছে" সনাক্ত করা হয়েছে) ।

পরবর্তী পন্থা এই সীমাবদ্ধতা এড়াতে।

একটি ভাল পদ্ধতি: পাইপলাইন এড়াতে

আপনি একসঙ্গে পাইপলাইন এড়াতে একটি ফিফো ব্যবহার করতে পারেন, একবার মৃত্যুদন্ড কার্যকর করার অনুমতি দেয় grep আয়। উদাহরণ স্বরূপ:

fifo=/tmp/tmpfifo.$$
mkfifo "${fifo}" || exit 1
tail -f logfile.log >${fifo} &
tailpid=$! # optional
grep -m 1 "Server Started" "${fifo}"
kill "${tailpid}" # optional
rm "${fifo}"

লাইন মন্তব্য সঙ্গে চিহ্নিত # optional মুছে ফেলা হতে পারে এবং প্রোগ্রাম এখনও কাজ করবে; tail এটি ইনপুট আরেকটি লাইন পড়তে না হওয়া পর্যন্ত বা কিছু অন্যান্য প্রক্রিয়া দ্বারা হত্যা করা হবে।

এই পদ্ধতির সুবিধাগুলি হল:

  • আপনি লগ ফাইল সংশোধন করতে হবে না
  • পদ্ধতির পাশাপাশি অন্যান্য ইউটিলিটি জন্য কাজ করে tail
  • এটি একটি জাতি অবস্থা থেকে ভোগ করে না
  • আপনি সহজেই ফেরত মান পেতে পারেন grep (অথবা আপনি ব্যবহার করছেন যে কোন বিকল্প কমান্ড)

এই পদ্ধতিতে নেতিবাচকতা জটিলতা, বিশেষ করে ফিফো পরিচালনা করা: আপনাকে নিরাপদভাবে একটি অস্থায়ী ফাইলের নাম তৈরি করতে হবে, এবং ব্যবহারকারীটি মাঝখানে Ctrl-C হিট করলেই অস্থায়ী ফিফো মুছে ফেলা হবে কিনা তা নিশ্চিত করতে হবে এই পান্ডুলিপি. এটি একটি ফাঁদ ব্যবহার করা যাবে।

বিকল্প পদ্ধতি: হত্যা করার জন্য একটি বার্তা পাঠান tail

আপনি পেতে পারেন tail পাইপলাইন স্তর এটি একটি সংকেত প্রেরণ করে প্রস্থান করার জন্য SIGTERM। চ্যালেঞ্জটি নির্ভরযোগ্যভাবে কোডে একই জিনিস দুটি জিনিস বুদ্ধিমান: tail এর পিআইডি এবং কিনা grep বহিষ্কৃত হয়েছে।

মত একটি পাইপলাইন সঙ্গে tail -f ... | grep ..., এটি সংরক্ষণ করার প্রথম পাইপলাইন মঞ্চ পরিবর্তন করা সহজ tail পিএইচডি ব্যাকগ্রাউন্ডিং দ্বারা একটি পরিবর্তনশীল tail এবং পড়া $!। এটি চালানোর দ্বিতীয় পাইপলাইন পর্যায়ে সংশোধন করা সহজ kill কখন grep প্রস্থান করে। সমস্যাটি হচ্ছে পাইপলাইনের দুটি স্তর পৃথক "নির্বাহ পরিবেশ" (পসিক্স স্ট্যান্ডার্ডের পরিভাষায়) মধ্যে চালানো হয় যাতে দ্বিতীয় পাইপলাইন স্তর প্রথম পাইপলাইন পর্যায়ে সেট করা কোনও ভেরিয়েবল পড়তে পারে না। শেল ভেরিয়েবলগুলি ব্যবহার না করেই, দ্বিতীয় পর্যায়টি অবশ্যই কোনভাবেই বের হওয়া উচিত tail এর পিআইডি যাতে এটি হত্যা করতে পারে tail কখন grep ফেরত, অথবা প্রথম পর্যায়ে কোনোভাবেই যখন অবহিত করা আবশ্যক grep আয়।

দ্বিতীয় পর্যায়ে ব্যবহার করতে পারে pgrep পেতে tail এর PID, কিন্তু এটি অবিশ্বাস্য (আপনি ভুল প্রক্রিয়াটি মিলতে পারে) এবং অ-পোর্টেবল ( pgrep POSIX মান দ্বারা নির্দিষ্ট করা হয় না)।

প্রথম পর্যায়ে পাইপের মাধ্যমে দ্বিতীয় পর্যায়ে পিআইডি পাঠাতে পারে echo PID ing, কিন্তু এই স্ট্রিং মিশ্রিত করা হবে tail এর আউটপুট। ডেমল্টিপ্লেক্সিংয়ের আউটপুটের উপর নির্ভর করে জটিল জটিল পালা স্কিম প্রয়োজন হতে পারে tail

দ্বিতীয় পাইপলাইন পর্যায়ে প্রথম পাইপলাইন পর্যায়টি অবহিত করার জন্য আপনি একটি ফিফো ব্যবহার করতে পারেন grep প্রস্থান করে। তারপর প্রথম পর্যায়ে হত্যা করতে পারেন tail। এখানে কিছু উদাহরণ কোড রয়েছে:

fifo=/tmp/notifyfifo.$$
mkfifo "${fifo}" || exit 1
{
    # run tail in the background so that the shell can
    # kill tail when notified that grep has exited
    tail -f logfile.log &
    # remember tail's PID
    tailpid=$!
    # wait for notification that grep has exited
    read foo <${fifo}
    # grep has exited, time to go
    kill "${tailpid}"
} | {
    grep -m 1 "Server Started"
    # notify the first pipeline stage that grep is done
    echo >${fifo}
}
# clean up
rm "${fifo}"

এই পদ্ধতির পূর্বের পদ্ধতির সমস্ত পেশাদার এবং বিপর্যয় রয়েছে, এটি ব্যতীত জটিল।

Buffering সম্পর্কে একটি সতর্কতা

POSIX stdin এবং stdout স্ট্রিমগুলিকে পুরোপুরি buffered করার অনুমতি দেয়, যার মানে tail এর আউটপুট দ্বারা প্রক্রিয়া করা হতে পারে না grep একটি ইচ্ছাকৃতভাবে দীর্ঘ সময় জন্য। জিএনইউ সিস্টেমে কোন সমস্যা নেই: জিএনইউ grep ব্যবহারসমূহ read(), যা সব বাফার, এবং GNU এড়ানো tail -f নিয়মিত কল করে তোলে fflush() যখন stdout লেখা। অ-জিএনইউ সিস্টেমগুলি অক্ষম বা নিয়মিত ফ্লাশ বাফারের জন্য বিশেষ কিছু করতে পারে।


আপনি সমাধান (অন্যদের মত আমি আপনাকে দোষারোপ করব না) আপনার নজরদারি শুরু হওয়ার আগে লগ ফাইলটিতে লিখিত জিনিসগুলি মিস করবে। দ্য tail -f শুধুমাত্র শেষ দশ লাইন আউটপুট, এবং তারপর সব নিম্নলিখিত আউটপুট হবে। এই উন্নতির জন্য, আপনি বিকল্প যোগ করতে পারেন -n 10000 লেজ পর্যন্ত তাই শেষ 10000 লাইন পাশাপাশি দেওয়া হয়।
Alfe

আরেকটি ধারণা: আপনার ফিফো সমাধান সোজা করা যেতে পারে, আমি মনে করি, আউটপুট পাস করে tail -f এফফো এবং মাধ্যমে grepping মাধ্যমে: mkfifo f; tail -f log > f & tailpid=$! ; grep -m 1 trigger f; kill $tailpid; rm f
Alfe

@ আলফঃ আমি ভুল হতে পারতাম, কিন্তু আমি বিশ্বাস করি tail -f log একটি ফিফোতে লিখুন লাইন-ভিত্তিক বাফারিংয়ের পরিবর্তে ব্লক-ভিত্তিক বাফারিং ব্যবহার করার জন্য কিছু সিস্টেম (উদাঃ, GNU / Linux) তৈরি করবে, যার অর্থ grep লগ ইন প্রদর্শিত হলে মিলিং লাইন দেখতে পারে না। সিস্টেম যেমন বাফার পরিবর্তন, একটি ইউটিলিটি প্রদান করতে পারে stdbuf GNU কোরআউট থেকে। যেমন একটি ইউটিলিটি অ পোর্টেবল হবে, তবে।
Richard Hansen

1
@Alfe: আসলে, মনে হচ্ছে POSIX টার্মিনালের সাথে ইন্টারঅ্যাক্ট করার ব্যতীত বাফার সম্পর্কে কিছু বলে না, তাই মানক দৃষ্টিকোণ থেকে আমি মনে করি আপনার সহজ সমাধানটি আমার জটিল হিসাবে ভাল। তবে আমি আসলে 100% নিশ্চিত নই যে বিভিন্ন বাস্তবায়ন আসলে প্রতিটি ক্ষেত্রে কীভাবে আচরণ করে।
Richard Hansen

আসলে, আমি এখন এমনকি সরল জন্য যান grep -q -m 1 trigger <(tail -f log) অন্যত্র প্রস্তাবিত এবং যে বাস সঙ্গে tail এটি প্রয়োজন তুলনায় পটভূমি আর একটি লাইন রান করে।
Alfe

13

আপনি যদি ব্যাশ ব্যবহার করেন (অন্তত, তবে মনে হয় এটি POSIX দ্বারা সংজ্ঞায়িত করা হয় না, তাই এটি কিছু শেলগুলিতে অনুপস্থিত হতে পারে), আপনি সিনট্যাক্স ব্যবহার করতে পারেন

grep -m 1 "Server Started" <(tail -f logfile.log)

এটি ইতিমধ্যে উল্লেখ করা FIFO সমাধানগুলির মতই অনেক বেশি কাজ করে, কিন্তু লেখার জন্য অনেক সহজ।


1
এই কাজ করে, কিন্তু আপনি পাঠাতে পর্যন্ত লেজ এখনও চলমান SIGTERM (Ctrl + C, প্রস্থান কমান্ড, অথবা এটি হত্যা করুন)
mems

3
@mems, লগ ফাইলে যেকোনো অতিরিক্ত লাইন কাজ করবে। দ্য tail এটি পড়বে, এটি আউটপুট করার চেষ্টা করুন এবং তারপরে একটি সিগপিপ পাবেন যা এটি বন্ধ করবে। সুতরাং, নীতিগতভাবে আপনি সঠিক; দ্য tail কখনও আবার লগ ফাইল লিখিত না হলে অনির্দিষ্টকালের জন্য চালাতে পারে। অনুশীলনে এটি অনেক লোকের জন্য খুব পরিষ্কার সমাধান হতে পারে।
Alfe

8

আমাকে @ 00prometheus উত্তরটি প্রসারিত করুন (যা সর্বোত্তমটি)।

হয়তো আপনি অনির্দিষ্টকালের জন্য অপেক্ষা করার পরিবর্তে একটি সময়সীমা ব্যবহার করা উচিত।

প্রদত্ত অনুসন্ধান শব্দ প্রদর্শিত বা একটি নির্দিষ্ট সময়সীমা পৌঁছেছেন না হওয়া পর্যন্ত নীচের bash ফাংশন অবরুদ্ধ হবে।

স্ট্রিং সময়সীমা মধ্যে খুঁজে পাওয়া যায় তাহলে প্রস্থান অবস্থা 0 হবে।

wait_str() {
  local file="$1"; shift
  local search_term="$1"; shift
  local wait_time="${1:-5m}"; shift # 5 minutes as default timeout

  (timeout $wait_time tail -F -n0 "$file" &) | grep -q "$search_term" && return 0

  echo "Timeout of $wait_time reached. Unable to find '$search_term' in '$file'"
  return 1
}

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

wait_server() {
  echo "Waiting for server..."
  local server_log="$1"; shift
  local wait_time="$1"; shift

  wait_file "$server_log" 10 || { echo "Server log file missing: '$server_log'"; return 1; }

  wait_str "$server_log" "Server Started" "$wait_time"
}

wait_file() {
  local file="$1"; shift
  local wait_seconds="${1:-10}"; shift # 10 seconds as default timeout

  until test $((wait_seconds--)) -eq 0 -o -f "$file" ; do sleep 1; done

  ((++wait_seconds))
}

এখানে আপনি এটি ব্যবহার করতে পারেন:

wait_server "/var/log/server.log" 5m && \
echo -e "\n-------------------------- Server READY --------------------------\n"

সুতরাং, যেখানে হয় timeout কমান্ড?
ayanamist

আসলে, ব্যবহার করে timeout এমন এক সার্ভারের জন্য অনির্দিষ্টকালের জন্য অপেক্ষা করতে না পারার একমাত্র নির্ভরযোগ্য উপায় যা শুরু করতে পারে না এবং ইতিমধ্যে ছাড়িয়ে গেছে।
gluk47

1
এই উত্তর সেরা। শুধু ফাংশন অনুলিপি করুন এবং এটি কল করুন, এটি খুব সহজ এবং পুনর্ব্যবহারযোগ্য
Hristo Vrigazov

6

তাই কিছু পরীক্ষা করার পর, আমি এই কাজটি করার জন্য দ্রুত 1-লাইন উপায় খুঁজে পেয়েছি। মনে হচ্ছে লেইলে -ফ বের হয়ে যাবে যখন জিপ ছাড়বে, কিন্তু সেখানে ধরা হবে। ফাইল খোলা এবং বন্ধ করা হলে এটি শুধুমাত্র ট্রিগার হতে প্রদর্শিত হবে। আমি grep খুঁজে মেলে যখন ফাঁকা স্ট্রিং ফাইল যোগ করে এই সম্পন্ন করেছি।

tail -f logfile |grep -m 1 "Server Started" | xargs echo "" >> logfile \;

আমি নিশ্চিত নই যে কেন ফাইলের খোলা / বন্ধ লেঙ্গুড়টি বুঝতে পারে যে পাইপটি বন্ধ আছে, তাই আমি এই আচরণের উপর নির্ভর করব না। কিন্তু এটা এখন জন্য কাজ বলে মনে হয়।

কারণটি বন্ধ হয়ে যায়, -এফ ফ্ল্যাগের বিপরীতে -এফ পতাকাটি দেখুন।


1
লগফিল কারণ যুক্ত কারণ এই কাজ করে tail অন্য লাইন আউটপুট, কিন্তু তারপর দ্বারা grep বহিষ্কৃত হয়েছে (সম্ভবত - সেখানে একটি জাতি শর্ত আছে)। যদি grep সময় দ্বারা exited হয়েছে tail আরেকটি লাইন লিখেছেন, tail একটি পেতে হবে SIGPIPE। যে কারণ tail সরাসরি প্রস্থান করতে।
Richard Hansen

1
এই পদ্ধতির অসুবিধা: (1) একটি জাতি শর্ত রয়েছে (এটি সর্বদা তাত্ক্ষণিকভাবে প্রস্থান নাও হতে পারে) (2) এটি লগ ফাইলটিতে অ্যাক্সেস লিখতে হবে (3) লগ ফাইলটি সংশোধন করার জন্য আপনাকে অবশ্যই ঠিক থাকতে হবে (4) আপনি এটি দূষিত করতে পারেন লগ ফাইল (5) এটি শুধুমাত্র জন্য কাজ করে tail (6) আপনি সহজেই পাইপলাইনের মাঝামাঝি পর্যায়টির রিটার্ন কোডটি সহজেই পেতে পারছেন না কারণ আপনি ডিফারেনট স্ট্রিং মিলগুলির ("সার্ভার শুরু" বনাম "সার্ভার শুরু" ব্যর্থ হয়েছে) উপর নির্ভর করে ভিন্নভাবে আচরণ করতে পারেন। একটি বিকল্প পদ্ধতি রয়েছে যা এই সমস্ত সমস্যা এড়াতে পারে - আমার উত্তরটি দেখুন।
Richard Hansen

6

বর্তমানে, প্রদত্ত হিসাবে, সব tail -f সমাধানগুলি এখানে পূর্বে লগ করা "সার্ভার শুরুর" লাইনটি বেছে নেওয়ার ঝুঁকিটি চালায় (যা আপনার নির্দিষ্ট ক্ষেত্রে একটি সমস্যা হতে পারে অথবা লগ লাইনের সংখ্যা এবং লগ ফাইল ঘূর্ণন / ট্রানকেশনের উপর নির্ভর করে)।

বেশি জটিল জিনিসগুলির পরিবর্তে, কেবল একটি স্মার্ট ব্যবহার করুন tail, হিসাবে bmike একটি পার্ল snippit সঙ্গে দেখানো। সবচেয়ে সহজ সমাধান এই retail যার সাথে ইন্টিগ্রেটেড regex সমর্থন আছে শুরু এবং বন্ধ করা শর্ত নিদর্শন:

retail -f -u "Server Started" server.log > /dev/null

এটি একটি স্বাভাবিক মত ফাইল অনুসরণ করবে tail -f প্রথম পর্যন্ত নতুন যে স্ট্রিং এর উদাহরণ প্রদর্শিত, তারপর প্রস্থান। (দ্য -u স্বাভাবিক "অনুসরণ" মোডে যখন ফাইলটি শেষ 10 টি লাইনগুলিতে বিদ্যমান লাইনগুলিতে ট্রিগার হয় না।)


আপনি যদি জিএনইউ ব্যবহার করেন tail (থেকে coreutils ), পরবর্তী সহজ বিকল্প ব্যবহার করা হয় --pid এবং একটি ফিফো (নামযুক্ত পাইপ):

mkfifo ${FIFO:=serverlog.fifo.$$}
grep -q -m 1 "Server Started" ${FIFO}  &
tail -n 0 -f server.log  --pid $! >> ${FIFO}
rm ${FIFO}

একটি FIFO ব্যবহার করা হয় কারণ একটি PID প্রাপ্ত এবং পাস করার জন্য প্রক্রিয়া আলাদাভাবে শুরু করা আবশ্যক। একটি ফিফো এখনও সময়মত লেখার জন্য প্রায় ঝুলন্ত একই সমস্যা থেকে ভুগছেন tail গ্রহণ করতে একটি সিগপিপ , ব্যবহার --pid বিকল্প তাই যে tail এটা যে বিজ্ঞপ্তি যখন exits grep বাতিল করা হয়েছে (প্রচলিতভাবে নিরীক্ষণ ব্যবহৃত লেখক পরিবর্তে প্রক্রিয়া পাঠক , কিন্তু tail সত্যিই যত্ন না)। পছন্দ -n 0 সঙ্গে ব্যবহার করা হয় tail যাতে পুরানো লাইন একটি ম্যাচ ট্রিগার না।


অবশেষে, আপনি একটি ব্যবহার করতে পারে রাষ্ট্রীয় লেজ , এটি বর্তমান ফাইল অফসেট সংরক্ষণ করবে তাই পরবর্তী আমন্ত্রণ শুধুমাত্র নতুন লাইন প্রদর্শন করে (এটি ফাইল ঘূর্ণন পরিচালনা করে)। এই উদাহরণটি পুরানো FWTK ব্যবহার করে retail *:

retail "${LOGFILE:=server.log}" > /dev/null   # skip over current content
while true; do
    [ "${LOGFILE}" -nt ".${LOGFILE}.off" ] && 
       retail "${LOGFILE}" | grep -q "Server Started" && break
    sleep 2
done

* উল্লেখ্য, একই নাম, পূর্ববর্তী বিকল্পের বিভিন্ন প্রোগ্রাম।

CPU-hogging লুপ করার পরিবর্তে, ফাইলের টাইমস্ট্যাম্পটি রাষ্ট্র ফাইলের সাথে তুলনা করুন ( .${LOGFILE}.off ), এবং ঘুমাও. ব্যবহার করুন " -T "যদি প্রয়োজন হয় তবে রাষ্ট্রের ফাইলের অবস্থান নির্দিষ্ট করতে, উপরেরটি বর্তমান ডিরেক্টরিটি অনুমান করে। শর্তটি ছেড়ে দেওয়া মুক্ত করুন, অথবা লিনাক্সে আপনি আরও কার্যকর ব্যবহার করতে পারেন inotifywait পরিবর্তে:

retail "${LOGFILE:=server.log}" > /dev/null
while true; do
    inotifywait -qq "${LOGFILE}" && 
       retail "${LOGFILE}" | grep -q "Server Started" && break
done

আমি একত্রিত করতে পারেন retail একটি সময়সীমার সাথে, যেমন: "যদি 120 সেকেন্ড পাস হয়ে গেছে এবং খুচরা এখনও লাইনটি পড়ে না, তবে একটি ত্রুটি কোড দিন এবং খুচরা প্রস্থান করুন"?
kiltek

@ কিলটেক জিএনইউ ব্যবহার করুন timeout (coreutils) আরম্ভ করা retail এবং টাইমআউট এ প্রস্থান কোড 1২4 টি চেক করুন ( timeout আপনি যে সময়টি সেট করে সেটিকে সেট করার পরে এটি ব্যবহার করতে পারবেন)
mr.spuratic

4

আপনি প্রক্রিয়া নিয়ন্ত্রণ এবং সংকেত মধ্যে পেতে হবে যেহেতু এটি একটি বিট চতুর হতে হবে। আরো ক্লিডি পিআইডি ট্র্যাকিং ব্যবহার করে একটি দুটি স্ক্রিপ্ট সমাধান হবে। ভাল নামযুক্ত পাইপ ব্যবহার করা হবে এটার মত.

আপনি কি শেল স্ক্রিপ্ট ব্যবহার করছেন?

একটি দ্রুত এবং নোংরা, একটি স্ক্রিপ্ট সমাধান জন্য - আমি ব্যবহার করে একটি পার্ল স্ক্রিপ্ট করতে হবে ফাইল: লেঙ্গুড়

use File::Tail;
$file=File::Tail->new(name=>$name, maxinterval=>300, adjustafter=>7);
while (defined($line=$file->read)) {
    last if $line =~ /Server started/;
}

সুতরাং লুপের ভিতরে মুদ্রণ করার পরিবর্তে, আপনি স্ট্রিং মিলের জন্য ফিল্টার করতে পারেন এবং আপনার স্ক্রিপ্টটি চালিয়ে যাওয়ার সময় লুপ থেকে বিরত থাকতে পারেন।

এই আপনি উভয় খুঁজছেন হয় পর্যবেক্ষক প্রবাহ নিয়ন্ত্রণ বাস্তবায়ন করতে একটু শিখতে জড়িত করা উচিত।


ব্যাশ ব্যবহার করে। আমার perl-fu যে শক্তিশালী না, কিন্তু আমি এই একটি শট দিতে হবে।
Alex Hofsteede

পাইপ ব্যবহার করুন - তারা bash ভালবাসা এবং bash তাদের ভালবাসেন। (এবং আপনার ব্যাকআপ সফ্টওয়্যার আপনার পাইপগুলি হিট করলে এটি আপনাকে সম্মান করবে)
bmike

maxinterval=>300 মানে এটি প্রতি পাঁচ মিনিটে ফাইল চেক করবে। যেহেতু আমি জানি যে আমার লাইন মুহূর্তে ফাইলটিতে উপস্থিত হবে, আমি আরো আক্রমনাত্মক ভোট ব্যবহার করছি: maxinterval=>0.2, adjustafter=>10000
Stephen Ostermiller

2

ফাইল প্রদর্শিত জন্য অপেক্ষা করুন

while [ ! -f /path/to/the.file ] 
do sleep 2; done

ফাইল প্রদর্শিত স্ট্রিং জন্য অপেক্ষা করুন

while ! grep "the line you're searching for" /path/to/the.file  
do sleep 10; done

https://superuser.com/a/743693/129669


2
এই ভোটের দুটি প্রধান ত্রুটি রয়েছে: 1. এটি আবার এবং আবার লগ মাধ্যমে যাচ্ছে গণনা সময় অপচয়। একটি বিবেচনা করুন /path/to/the.file যা 1.4 গিগাবাইট বড়; তারপর এটা স্পষ্ট যে এটি একটি সমস্যা। 2. এটি লগ ইন এন্ট্রি হাজির হলে প্রয়োজনের চেয়ে বেশি অপেক্ষা করে, সবচেয়ে খারাপ ক্ষেত্রে 10s।
Alfe

2

আমি এই চেয়ে একটি ক্লিনার সমাধান কল্পনা করতে পারবেন না:

#!/usr/bin/env bash
# file : untail.sh
# usage: untail.sh logfile.log "Server Started"
(echo $BASHPID; tail -f $1) | while read LINE ; do
    if [ -z $TPID ]; then
        TPID=$LINE # the first line is used to store the previous subshell PID
    else
        echo "$LINE"; [[ "$LINE" == *"${*:2}"* ]] && kill -3 $TPID && break
    fi
done

ঠিক আছে, হয়তো নামটি উন্নতি সাপেক্ষে হতে পারে ...

সুবিধাদি:

  • এটা কোন বিশেষ ইউটিলিটি ব্যবহার করে না
  • এটা ডিস্ক লিখতে না
  • এটা gracefully লেজ ছেড়ে এবং পাইপ বন্ধ করে
  • এটা খুবই ছোট এবং বুঝতে সহজ

2

আপনি প্রয়োজন যে পুচ্ছ প্রয়োজন নেই। আমি মনে করি ঘড়ি কমান্ড আপনি খুঁজছেন কি। ঘড়ি কমান্ডটি একটি ফাইলের আউটপুটকে নিরীক্ষণ করে এবং এর সাথে পরিসমাপ্তি করা যেতে পারে -G আউটপুট পরিবর্তন যখন বিকল্প।

watch -g grep -m 1 "Server Started" logfile.log && Yournextaction

1
লাইন ফাইলটিতে লাইন উপস্থিত হওয়ার পরে এটি প্রতি দুই সেকেন্ডে একবার চালানো হয়। এছাড়াও, লগ ফাইলটি খুব বড় হলে এটি ভাল কাজ করে না।
Richard Hansen


1

অ্যালেক্স আমি এই এক আপনাকে অনেক সাহায্য করবে মনে হয়।

tail -f logfile |grep -m 1 "Server Started" | xargs echo "" >> /dev/null ;

এই কমান্ড লগফিলের উপর একটি এন্ট্রি দেবে না কিন্তু নীরবভাবে grep করবে ...


1
এই কাজ করবে না - আপনি যোগ করতে হবে logfile অন্যথায় এটি একটি ইচ্ছাকৃতভাবে দীর্ঘ সময় হতে পারে আগে tail আউটপুট অন্য লাইন এবং যে সনাক্ত করে grep মারা গেছে (মাধ্যমে SIGPIPE )।
Richard Hansen

1

এখানে একটি আরও ভাল সমাধান যা আপনাকে লগফাইলে লিখতে হবে না যা কিছু ক্ষেত্রে বিপজ্জনক বা এমনকি অসম্ভব।

sh -c 'tail -n +0 -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'

বর্তমানে এটি শুধুমাত্র একটি পার্শ্ব প্রতিক্রিয়া আছে, দী tail পরবর্তী লাইনে লগ লিখিত হয় না হওয়া পর্যন্ত প্রক্রিয়া পটভূমিতে থাকবে।


tail -n +0 -f ফাইলের শুরু থেকে শুরু হয়। tail -n 0 -f ফাইল শেষ থেকে শুরু হয়।
Stephen Ostermiller

1
আমি অন্য পার্শ্ব প্রতিক্রিয়া পেতে: myscript.sh: line 14: 7845 Terminated sh -c 'tail...
Stephen Ostermiller

আমি বিশ্বাস করি যে "পরবর্তী তালিকা" এই উত্তরটিতে "পরবর্তী লাইন" হওয়া উচিত।
Stephen Ostermiller

1

এখানে অন্যান্য সমাধান বিভিন্ন বিষয় আছে:

  • লুপ সময় লগিং প্রক্রিয়া ইতিমধ্যে ডাউন বা ডাউন হয় যদি তারা অনির্দিষ্টকালের জন্য চালানো হবে
  • শুধুমাত্র লগ করা উচিত যে একটি লগ সম্পাদনা
  • অপ্রয়োজনীয়ভাবে একটি অতিরিক্ত ফাইল লেখা
  • অতিরিক্ত যুক্তি জন্য অনুমতি দেয় না

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

function startTomcat {
    loggingProcessStartCommand="${CATALINA_HOME}/bin/startup.sh"
    loggingProcessOwner="root"
    loggingProcessCommandLinePattern="${JAVA_HOME}"
    logSearchString="org.apache.catalina.startup.Catalina.start Server startup"
    logFile="${CATALINA_BASE}/log/catalina.out"

    lineNumber="$(( $(wc -l "${logFile}" | awk '{print $1}') + 1 ))"
    ${loggingProcessStartCommand}
    while [[ -z "$(sed -n "${lineNumber}p" "${logFile}" | grep "${logSearchString}")" ]]; do
        [[ -z "$(ps -ef | grep "^${loggingProcessOwner} .* ${loggingProcessCommandLinePattern}" | grep -v grep)" ]] && { echo "[ERROR] Tomcat failed to start"; return 1; }
        [[ $(wc -l "${logFile}" | awk '{print $1}') -lt ${lineNumber} ]] && continue
        #sed -n "${lineNumber}p" "${logFile}"
        let lineNumber++
    done
    #sed -n "${lineNumber}p" "${logFile}"
    echo "[INFO] Tomcat has started"
}

1

দ্য tail কমান্ড ব্যাকগ্রাউন্ড করা যাবে এবং এর পিন প্রতি প্রতিধ্বনিত grep subshell। মধ্যে grep subshell একটি ফাঁদ হ্যান্ডলার EXIT উপর হত্যা করতে পারেন tail কমান্ড।

( (sleep 1; exec tail -f logfile.log) & echo $! ; wait ) | 
     (trap 'kill "$pid"' EXIT; pid="$(head -1)"; grep -m 1 "Server Started")

1

তাদের সব পড়ুন। tldr: grep থেকে লেজ সমাপ্তির decouple।

দুটি ফর্ম সবচেয়ে সুবিধাজনক হয়

( tail -f logfile.log & ) | grep -q "Server Started"

এবং আপনি bash আছে

grep -m 1 "Server Started" <(tail -f logfile.log)

কিন্তু পটভূমিতে বসে যে লেজটি আপনাকে বিরক্ত করে, এখানে একটি পিনো বা অন্য কোনো উত্তরের চেয়ে নিছক উপায় রয়েছে। ব্যাশ প্রয়োজন।

coproc grep -m 1 "Server Started"
tail -F /tmp/x --pid $COPROC_PID >&${COPROC[1]}

অথবা যদি এটি পুচ্ছ না হয় যা জিনিস উৎপাদনের হয়,

coproc command that outputs
grep -m 1 "Sever Started" ${COPROC[0]}
kill $COPROC_PID

0

Inotify ব্যবহার করার চেষ্টা করুন (inotifywait)

আপনি কোনও ফাইল পরিবর্তনের জন্য inotifywait সেট আপ করেন, তারপরে grep এর সাথে ফাইলটি পরীক্ষা করুন, যদি না পাওয়া যায় তবে ইনটাইফাইওয়াটটি পুনরায় চালু করুন, যদি লুপটি প্রস্থান করা হয় ... স্মৃতির মতো


এই ভাবে, দী সমগ্র ফাইলটি প্রতিবার কিছু লেখা হলে পুনঃচেষ্টা করা হবে। লগ ফাইলের জন্য ভাল কাজ করে না।
grawity

1
আরেকটি উপায় হল দুটি স্ক্রিপ্ট তৈরি করা: 1. tail -f logfile.log | grep -m 1 "সার্ভার শুরু" & gt; / tmp / পাওয়া যায় 2. firstscript.sh & amp; MYPID = $!; inotifywait -e পরিবর্তন / tmp / পাওয়া; হত্যা - KILL - $ MYPID
Evengard

আমি আপনাকে পিআইডি ক্যাপচার দেখানোর জন্য এবং তারপর inotifywait ব্যবহার করে আপনার উত্তরটি সম্পাদনা করতে চাই - একটি মার্জিত সমাধান যা grep তে ব্যবহৃত কারো জন্য উপলব্ধি করা সহজ তবে আরও বেশি পরিশীলিত সরঞ্জামের প্রয়োজন।
bmike

একটি পিআইডি আপনি ক্যাপচার করতে চান? আপনি কি চান তা একটু বিশদ ব্যাখ্যা করার জন্য আমি এটি করতে চেষ্টা করতে পারি
Evengard

0

লাইনে লেখা যত তাড়াতাড়ি আপনি ছেড়ে যেতে চান, কিন্তু আপনি একটি সময়সীমার পরে চলে যেতে চান:

if (timeout 15s tail -F -n0 "stdout.log" &) | grep -q "The string that says the startup is successful" ; then
    echo "Application started with success."
else
    echo "Startup failed."
    tail stderr.log stdout.log
    exit 1
fi
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.