কোনও ফাইলের শেষে থেকে শুরু পর্যন্ত গ্রেপ করুন


38

আমার প্রায় 30.000.000 লাইন (রেডিয়াস অ্যাকাউন্টিং) সহ একটি ফাইল রয়েছে এবং আমার প্রদত্ত প্যাটার্নের শেষ ম্যাচটি খুঁজে বের করতে হবে।

আদেশ:

tac accounting.log | grep $pattern

আমার যা প্রয়োজন তা দেয় তবে এটি খুব ধীর কারণ ওএসকে প্রথমে পুরো ফাইলটি পড়তে হবে এবং তারপরে পাইপে প্রেরণ করতে হবে।

সুতরাং, আমার দ্রুত এমন কিছু দরকার যা শেষ লাইন থেকে প্রথম পর্যন্ত ফাইলটি পড়তে পারে।

উত্তর:


44

tacআপনি যদি প্রথম ম্যাচের পরে থামার জন্য grep -m 1(জিএনইউ অনুমান করে grep) ব্যবহার করেন তবেই সহায়তা করে grep:

tac accounting.log | grep -m 1 foo

থেকে man grep:

   -m NUM, --max-count=NUM
          Stop reading a file after NUM matching lines.  

আপনার প্রশ্নের উদাহরণে উভয় tacএবং grepসম্পূর্ণ ফাইলটি প্রক্রিয়া করা প্রয়োজন সুতরাং tacএটির অর্থহীন।

সুতরাং, আপনি যদি grep -mনা ব্যবহার tacকরেন তবে একেবারেই ব্যবহার করবেন না , grepশেষ ম্যাচটি পাওয়ার জন্য আউটপুটকে কেবল পার্স করুন :

grep foo accounting.log | tail -n 1 

পার্ল বা অন্য কোনও স্ক্রিপ্টিং ভাষা ব্যবহার করার জন্য আরেকটি উপায় হবে। উদাহরণস্বরূপ (যেখানে $pattern=foo):

perl -ne '$l=$_ if /foo/; END{print $l}' file

অথবা

awk '/foo/{k=$0}END{print k}' file

1
আমি ট্যাক ব্যবহার করছি কারণ আমাকে প্রদত্ত প্যাটার্নের শেষ ম্যাচটি খুঁজে পাওয়া দরকার। আপনার পরামর্শ "গ্রেপ-এম 1" ব্যবহার করে কার্যকর করার সময়টি 0m0.597s থেকে 0m0.007s \ o / এ চলে যায়। সবাইকে ধন্যবাদ!
হাবনার কোস্টার

1
@ হাবনারকোস্টা আপনাকে খুব স্বাগতম welcome আমি বুঝতে পারছি আপনি কেন ব্যবহার করছেন tac, আমার বক্তব্যটি হ'ল আপনি যদি না ব্যবহার করেন তবে এটি কার্যকর হয় না -mকারণ ফাইলটি এখনও দুটি প্রোগ্রামের মাধ্যমে পুরোপুরি পড়তে হবে। অন্যথায়, আপনি কেবল সমস্ত ঘটনা সন্ধান করতে এবং আমার সাথে কেবল শেষটি রাখতে পারেন tail -n 1
টেরডন

6
আপনি কেন "ট্যাক [...] পুরো ফাইলটি প্রক্রিয়া করা প্রয়োজন" বলছেন? ট্যাক প্রথম জিনিসটি ফাইলটির শেষের দিকে অনুসন্ধান করা এবং শেষ থেকে একটি ব্লক পড়া। আপনি নিজেই এটি স্ট্রেস (1) দ্বারা যাচাই করতে পারেন। যখন একত্রিত করা হয় grep -m, এটি বেশ দক্ষ হওয়া উচিত।
ক্যাম এ

1
@ ক্যাম যখন grep -mএটির সাথে মিলিত হয়। ওপি ব্যবহার করছিল না -mতাই গ্রেপ এবং ট্যাক উভয়ই পুরো বিষয়টি প্রক্রিয়াজাত করছিল।
terdon

আপনি দয়া করে awkলাইনের অর্থটি প্রসারিত করতে পারেন ?
সোপালাজো ডি অ্যারিরিজ

12

কারণ কেন

tac file | grep foo | head -n 1

প্রথম ম্যাচে থামছে না বাফারিংয়ের কারণে।

সাধারণত, head -n 1একটি লাইন পড়ার পরে প্রস্থান করে। সুতরাং grepএটির দ্বিতীয় লাইনটি লেখার সাথে সাথে একটি সিগপাইপ পাওয়া এবং প্রস্থান করা উচিত।

তবে যা হয় তা হ'ল কারণ এর আউটপুট কোনও টার্মিনালে যাচ্ছে না, grepএটি বাফার করে। এটি, এটি যথেষ্ট পরিমাণে জমে না হওয়া পর্যন্ত এটি লিখছে না (জিএনইউ গ্রেপ সহ আমার পরীক্ষায় 4096 বাইট)।

এর অর্থ কী grepএটি 8192 বাইট ডেটা লিখে দেওয়ার আগে প্রস্থান করবে না, সম্ভবত বেশ কয়েকটি লাইন।

জিএনইউ দিয়ে grepআপনি এটি ব্যবহার করে তাড়াতাড়ি প্রস্থান --line-bufferedকরতে পারবেন যা টার্মিনালে যায় কিনা তা নির্বিশেষে পাওয়া যায় তবেই এটি লাইন লিখতে বলে lines সুতরাং grepএটি খুঁজে দ্বিতীয় লাইনে প্রস্থান করবে।

তবে জিএনইউর সাথে grepযাইহোক, আপনি এর -m 1পরিবর্তে @ টেরডন দেখিয়ে ব্যবহার করতে পারেন , এটি প্রথম ম্যাচে প্রস্থান হওয়ার সাথে সাথে আরও ভাল।

যদি আপনার grepজিএনইউ না হয় grepতবে আপনি তার পরিবর্তে sedবা ব্যবহার করতে পারেন awk। তবে tac জিএনইউ কমান্ড হওয়ার কারণে আমি সন্দেহ করি যে আপনি এমন একটি সিস্টেম পাবেন tacযেখানে grepজিএনইউ নেই grep

tac file | sed "/$pattern/!d;q"                             # BRE
tac file | P=$pattern awk '$0 ~ ENVIRON["P"] {print; exit}' # ERE

কিছু সিস্টেমকে tail -rজিএনইউর মতো কাজ করতে tacহয়।

দ্রষ্টব্য, নিয়মিত (সন্ধানযোগ্য) ফাইলগুলির জন্য tacএবং tail -rদক্ষ কারণ তারা ফাইলগুলি পিছিয়ে পড়ে, তারা কেবল ফাইলটিকে পিছনে ছাপানোর আগে মেমরিতে পুরোপুরি পড়ছে না ( @ স্ল্যামের সিড পদ্ধতির হিসাবে বা tacনিয়মিত নয় এমন ফাইলগুলিতে) ।

যেসব সিস্টেমে tacনাও tail -rউপলভ্য নয়, কেবলমাত্র বিকল্পগুলি হ'ল ব্যাকগ্রাউন্ড-রিডিংটি প্রোগ্রামিং ভাষা perlবা ব্যবহারের মতো ভাষা দিয়ে হাতে প্রয়োগ করা হবে:

grep -e "$pattern" file | tail -n1

বা:

sed "/$pattern/h;$!d;g" file

তবে এর অর্থ সমস্ত ম্যাচ সন্ধান করা এবং কেবল শেষটি মুদ্রণ করা।


4

এখানে একটি সম্ভাব্য সমাধান যা প্যাটার্নের প্রথম ঘটনার অবস্থানটি শেষ থেকে খুঁজে পাবে:

tac -s "$pattern" -r accounting.log | head -n 1

এটি নীচের মত -sএবং -rএরগুলির স্যুইচগুলি ব্যবহার tacকরে:

-s, --separator=STRING
use STRING as the separator instead of newline

-r, --regex
interpret the separator as a regular expression

রেখার সূচনা এবং প্যাটার্নের মধ্যবর্তী যা কিছু আপনি হারিয়ে ফেলবেন তা বাদ দিয়ে।
ychaouche

2

সেড ব্যবহার

@ টেরডনের উত্তরের জবাবটি ব্যবহার করে কিছু বিকল্প পদ্ধতি দেখানো হচ্ছে sed:

$ sed '1!G;h;$!d' file | grep -m 1 $pattern
$ sed -n '1!G;h;$p' file | grep -m 1 $pattern

উদাহরণ

$ seq 10 > file

$ sed '1!G;h;$!d' file | grep -m 1 5
5

$ sed -n '1!G;h;$p' file | grep -m 1 5
5

পার্ল ব্যবহার করা

বোনাস হিসাবে এখানে পার্লের মনে রাখার জন্য কিছুটা সহজ স্বরলিপি:

$ perl -e 'print reverse <>' file | grep -m 1 $pattern

উদাহরণ

$ perl -e 'print reverse <>' file | grep -m 1 5
5

1
যে (বিশেষ করে sedএকটি করে) সম্ভবত তুলনায় ধীর মাত্রার বিভিন্ন আদেশ হতে grep 5 | tail -n1বা sed '/5/h;$!d;g'। এটি সম্ভাব্য প্রচুর স্মৃতি ব্যবহার করবে। আপনি এখনও জিএনইউ ব্যবহার করছেন বলে এটি খুব বেশি বহনযোগ্য নয় grep -m
স্টাফেন চেজেলাস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.