কিভাবে স্ট্যান্ডার্ড ত্রুটি স্ট্রিম (স্টডার) গ্রেপ করবেন?


76

আমি একটি অডিও ক্লিপের মেটা তথ্য পেতে ffmpeg ব্যবহার করছি। তবে আমি এটি গ্রেপ করতে অক্ষম।

    $ ffmpeg -i 01-Daemon.mp3  |grep -i Duration
    FFmpeg version SVN-r15261, Copyright (c) 2000-2008 Fabrice Bellard, et al.
      configuration: --prefix=/usr --bindir=/usr/bin 
      --datadir=/usr/share/ffmpeg --incdir=/usr/include/ffmpeg --libdir=/usr/lib
      --mandir=/usr/share/man --arch=i386 --extra-cflags=-O2 
      ...

আমি পরীক্ষা করে দেখেছি, এই ffmpeg আউটপুটটি stderr এর দিকে পরিচালিত।

$ ffmpeg -i 01-Daemon.mp3 2> /dev/null

সুতরাং আমি মনে করি যে গ্রেপ ম্যাচিং লাইনগুলি ধরার জন্য ত্রুটি স্ট্রিমটি পড়তে অক্ষম। কীভাবে আমরা গ্রেপকে ত্রুটি প্রবাহটি পড়তে সক্ষম করতে পারি?

নিক্সক্রাফ্ট লিঙ্কটি ব্যবহার করে , আমি আদর্শ ত্রুটি স্ট্রিমটিকে স্ট্যান্ডার্ড আউটপুট প্রবাহে পুনঃনির্দেশিত করেছি, তারপরে গ্রেপ কাজ করেছিল।

$ ffmpeg -i 01-Daemon.mp3 2>&1 | grep -i Duration
  Duration: 01:15:12.33, start: 0.000000, bitrate: 64 kb/s

তবে আমরা যদি স্টাডারকে স্টডআউটে পুনর্নির্দেশ করতে না চাই?


1
আমি বিশ্বাস করি যে grepকেবলমাত্র স্টাডাউটে অপারেট করতে পারে (যদিও আমি এটির ব্যাক আপ করার জন্য ক্যানোনিকাল উত্সটি পাই না), যার অর্থ যে কোনও প্রবাহকে প্রথমে স্টডআউটে রূপান্তরিত করা দরকার।
স্টিফান লাসিউস্কি

9
@ স্টেফান: grepকেবল স্টিডিনে কাজ করতে পারে। এটি শেলের দ্বারা তৈরি পাইপ যা গ্রেপ এর স্টিডিনকে অন্য কমান্ডের স্টডআউটের সাথে সংযুক্ত করে। এবং শেলটি একটি স্ট্ডআউটকে কেবল একটি স্টিডিনের সাথে সংযুক্ত করতে পারে।
গিলস

ওফ, আপনি ঠিক বলেছেন। আমি মনে করি এটি বলতে আমি যা বোঝাতে চেয়েছিলাম, আমি কেবল এটির মাধ্যমে ভাবিনি। ধন্যবাদ @ গাইলস।
স্টেফান লাসিউইস্কি

আপনি কি এটি এখনও স্টডআউট মুদ্রণ করতে চান?
মাইকেল

উত্তর:


52

আপনি যদি bashবেনামে পাইপ নিয়োগ না করেন তবে ফুনেহে যা বলেছেন তার সংক্ষেপে সংক্ষেপে:

ffmpeg -i 01-Daemon.mp3 2> >(grep -i Duration)


3
+1 ভাল! কেবল বাশ, তবে বিকল্পগুলির চেয়ে পরিষ্কার।
মাইকেল

1
cpআউটপুট চেক করতে আমি এটি ব্যবহার করেছিcp -r dir* to 2> >(grep -v "svn")
বেটলিস্ট

5
আপনি আবার দ্বারা stderr উপর ফিল্টার পুনঃনির্দেশিত আউটপুট চান, একটি যোগ >&2, যেমনcommand 2> >(grep something >&2)
tlo

2
এটি কীভাবে কাজ করে তা দয়া করে ব্যাখ্যা করুন। 2>stderr ফাইল এ পুনঃনির্দেশ, আমি এটি পেতে। এটি ফাইল থেকে পড়ে >(grep -i Duration)। তবে ফাইলটি কখনও স্টোর হয় না? এই কৌশলটি কী বলা হয় তাই আমি এটি সম্পর্কে আরও পড়তে পারি?
মার্কো আলেলিš

1
এটি তৈরি করতে "সিনট্যাকটিক চিনি" এবং একটি পাইপ (ফাইল নয়) এবং সম্পূর্ণরূপে পাইপটি সরিয়ে ফেলা হয়। তারা কার্যকরভাবে বেনামে থাকে কারণ তাদের ফাইল সিস্টেমে কোনও নাম দেওয়া হয়নি। বাশ এই প্রক্রিয়াটি বিকল্প বলে।
Jé ক্যু 25'18

48

স্টাডাউট থেকে স্টিডিন ছাড়া অন্য কোনও সাধারণ শেল (এমনকি zsh) পাইপের অনুমতি দেয় না। তবে সমস্ত বোর্ন-স্টাইলের শেলগুলি ফাইল বর্ণনাকারী পুনরায় নিয়োগ (যেমন রয়েছে 1>&2) সমর্থন করে। সুতরাং আপনি অস্থায়ীভাবে stdout এফডি 3 এ এবং স্টার্ডারকে স্টডআউটে ডাইভার্ট করতে পারেন এবং পরে এফডি 3 পিছনে স্টাডাউটের দিকে রাখতে পারেন। যদি stuffস্টাডাউটে কিছু আউটপুট এবং স্টার্ডারে কিছু আউটপুট উত্পাদন করে এবং আপনি filterস্ট্যান্ডার্ড আউটপুটটি আউটচুড রেখে ত্রুটি আউটপুটটিতে প্রয়োগ করতে চান , আপনি ব্যবহার করতে পারেন { stuff 2>&1 1>&3 | filter 1>&2; } 3>&1

$ stuff () {
  echo standard output
  echo more output
  echo standard error 1>&2
  echo more error 1>&2
}
$ filter () {
  grep a
}
$ { stuff 2>&1 1>&3 | filter 1>&2; } 3>&1
standard output
more output
standard error

এই পদ্ধতির কাজ করে। দুর্ভাগ্যক্রমে, আমার ক্ষেত্রে, যদি একটি শূন্য-না ফেরতের মান ফিরে আসে তবে তা হারিয়ে যায় - প্রত্যাবর্তিত মানটি আমার জন্য 0। এটি সর্বদা না ঘটতে পারে তবে আমি বর্তমানে যা দেখছি সে ক্ষেত্রে এটি ঘটে। এটি সংরক্ষণ করার কোনও উপায় আছে?
ফাহিম মিঠা

2
@ ফাহিমমিঠা আপনি কী করছেন তা নিশ্চিত নন, তবে সম্ভবত pipestatusসহায়তা করবে
গিলস

1
@ ফাহিমমিঠা, set -o pipefailত্রুটির স্থিতিতে আপনি কী করতে চান তার উপর নির্ভর করে এখানেও সহায়ক হতে পারে। (উদাহরণস্বরূপ, যদি আপনি set -eকোনও ত্রুটি থেকে ব্যর্থ হয়ে থাকেন, আপনি সম্ভবত set -o pipefailএটিও চান ))
ওয়াইল্ডকার্ড

@ ওল্ডকার্ড হ্যাঁ, আমি set -eকোনও ত্রুটি ব্যর্থ করতে চালু করেছি।
ফাহিম মিঠা

rcশেল বংশীধ্বনিতুল্য দ্বারা stderr পারেন। দেখুন আমার উত্তর নিচে।
রোল্ফ

20

এটি ফুনেহেহের "টেম্প ফাইল ট্রিক" এর অনুরূপ, তবে পরিবর্তে একটি নামযুক্ত পাইপ ব্যবহার করে, ফলাফলগুলি যখন আউটপুট হয় তখন কিছুটা কাছাকাছি ফলাফল পেতে দেয়, যা দীর্ঘকাল চলমান কমান্ডগুলির জন্য কার্যকর হতে পারে:

$ mkfifo mypipe
$ command 2> mypipe | grep "pattern" mypipe

এই নির্মাণে, স্ট্ডারকে "মাইপাইপ" নামক পাইপের দিকে পরিচালিত করা হবে। যেহেতু grepএকটি ফাইল আর্গুমেন্টের সাথে ডাকা হয়েছিল তাই এটি তার ইনপুটটির জন্য STDIN- তে নজর দেবে না। দুর্ভাগ্যক্রমে, কাজ শেষ হয়ে গেলে আপনাকে এখনও সেই নামক পাইপটি পরিষ্কার করতে হবে।

আপনি যদি ব্যাশ 4 ব্যবহার করছেন তবে এর জন্য একটি শর্টকাট সিনট্যাক্স রয়েছে command1 2>&1 | command2, যা command1 |& command2। তবে আমি বিশ্বাস করি যে এটি নিখুঁতভাবে একটি সিনট্যাক্স শর্টকাট, আপনি এখনও STDERR কে STDOUT এ পুনঃনির্দেশ করছেন।



1
|&ফুলে যাওয়া রুবি স্ট্যাডার স্ট্যাকের চিহ্নগুলি পরিষ্কার করার জন্য এই বাক্য গঠনটি নিখুঁত। খুব বেশি ঝামেলা ছাড়াই শেষ পর্যন্ত গ্রেপ্তার করতে পারি।
pgr

8

গিলস এবং স্টিফান লাসিউস্কির উত্তর দুটিই ভাল তবে এই পদ্ধতিটি সহজ:

ffmpeg -i 01-Daemon.mp3 2>&1 >/dev/null | grep "pattern"

আমি ধরে নিচ্ছি আপনি ffmpeg'sস্টাডআউট প্রিন্ট করতে চান না ।

কিভাবে এটা কাজ করে:

  • পাইপ আগে
    • ffmpeg এবং গ্রেপ শুরু হয়, ffmpeg এর স্টাডআউট গ্রেপের স্টিডিনে যায়
  • পুনঃনির্দেশগুলি পরবর্তী, বাম থেকে ডানে
    • ffmpeg এর stderr তার stdout যাই হোক না কেন সেট করা হয় (বর্তমানে পাইপ)
    • ffmpeg এর stdout / dev / নাল সেট করা হয়েছে

এই বর্ণনাটি আমার কাছে বিভ্রান্তিকর। শেষ দুটি বুলেট আমাকে "stdout এ স্টেডার পুনর্নির্দেশ" ভাবতে বাধ্য করে, তারপরে "stdout (এখন stderr সহ, এখন) / dev / নাল" এ পুনঃনির্দেশ করুন। তবে এটি এটি যা করছে তা নয়। এই বিবৃতিগুলি বিপরীত বলে মনে হচ্ছে।
স্টিভ

1
@ বুলেট দ্বিতীয় বুলেটে "স্টেডার সহ" নেই। আপনি কি ইউনিক্স.স্ট্যাকেক্সেঞ্জাওয়েজ / প্রশ্নগুলি / 637660০ / অর্ডার-অফ-রেকর্ডেশন দেখেছেন ?
মাইকেল

না, আমি আপনাকে ইংরেজিতে এটি কীভাবে বর্ণনা করেছি তার অর্থ এটি আমার । আপনার দেওয়া লিঙ্কটি যদিও খুব কার্যকর।
স্টিভ

এটিকে কেন / দেব / নালায় পাঠানো দরকার ছিল?
কনভলজিৎ সিং

7

এই পরীক্ষাগুলিতে ব্যবহৃত স্ক্রিপ্টের জন্য নীচে দেখুন।

গ্রেপ কেবল স্টিডিনে কাজ করতে পারে, সুতরাং আপনাকে স্টার্ডার স্ট্রিমটি এমন একটি ফর্মের মধ্যে রূপান্তর করতে হবে যা গ্রেপ পার্স করতে পারে।

সাধারণত, stdout এবং stderr উভয়ই আপনার স্ক্রিনে মুদ্রিত হয়:

$ ./stdout-stderr.sh
./stdout-stderr.sh: Printing to stdout
./stdout-stderr.sh: Printing to stderr

স্টাডাউট আড়াল করতে, তবে এখনও মুদ্রণকারী স্ট্যান্ডার এটি করুন:

$ ./stdout-stderr.sh >/dev/null
./stdout-stderr.sh: Printing to stderr

কিন্তু গ্রেপ স্টাডারের উপর কাজ করবে না! আপনি নীচের কমান্ডটি এমন লাইনগুলিকে দমন করতে আশা করতে পারেন যার মধ্যে 'এরর' রয়েছে তবে এটি তা করে না।

$ ./stdout-stderr.sh >/dev/null |grep --invert-match err
./stdout-stderr.sh: Printing to stderr

সমাধান এখানে।

নিম্নলিখিত বাশ বাক্য গঠনটি আউটপুটকে স্টডআউটে লুকিয়ে রাখবে, তবে এখনও স্ট্ডার দেখিয়ে দেবে। প্রথমে আমরা stdout কে / dev / null তে পাইপ করি, তারপরে আমরা stderr কে stdout এ রূপান্তর করি, কারণ ইউনিক্স পাইপগুলি কেবল stdout এ কাজ করবে। আপনি এখনও পাঠ্যটি গ্রেপ করতে পারেন।

$ ./stdout-stderr.sh 2>&1 >/dev/null | grep err
./stdout-stderr.sh: Printing to stderr

(নোট করুন যে উপরের কমান্ডটি তখন ভিন্ন./command >/dev/null 2>&1 , যা একটি খুব সাধারণ আদেশ)।

এখানে স্ক্রিপ্ট পরীক্ষার জন্য ব্যবহৃত হয়। এটি স্টাডাউট থেকে একটি লাইন এবং স্টারডারে একটি লাইন মুদ্রণ করে:

#!/bin/sh

# Print a message to stdout
echo "$0: Printing to stdout"
# Print a message to stderr
echo "$0: Printing to stderr" >&2

exit 0

আপনি যদি পুনঃনির্দেশগুলি চারপাশে স্যুইচ করেন তবে আপনার সমস্ত ধনুর্বন্ধনী প্রয়োজন নেই। শুধু কর ./stdout-stderr.sh 2>&1 >/dev/null | grep err
মাইকেল

3

যখন আপনি একটি কমান্ডের আউটপুটটিকে অন্য কমান্ডে ব্যবহার করে (ব্যবহার করছেন |), আপনি কেবলমাত্র স্ট্যান্ডার্ড আউটপুটটিকে পুনর্নির্দেশ করছেন। সুতরাং যে কারণ ব্যাখ্যা করা উচিত

ffmpeg -i 01-Daemon.mp3 | grep -i Duration

আপনি যা চেয়েছিলেন তা আউটপুট দেয় না (যদিও এটি কাজ করে)।

যদি আপনি ত্রুটি আউটপুটটিকে স্ট্যান্ডার্ড আউটপুটে পুনর্নির্দেশ করতে না চান তবে আপনি কোনও ফাইলের মধ্যে ত্রুটি আউটপুট পুনর্নির্দেশ করতে পারেন, তারপরে এটি গ্রেপ করুন

ffmpeg -i 01-Daemon.mp3 2> /tmp/ffmpeg-error
grep -i Duration /tmp/ffmpeg-error

ধন্যবাদ। it does work, though, আপনার মানে এটি আপনার মেশিনে কাজ করছে? দ্বিতীয়ত, আপনি পাইপ ব্যবহার হিসাবে চিহ্নিত করেছেন আমরা কেবল স্টডআউট পুনর্নির্দেশ করতে পারি। আমি এমন কিছু কমান্ড বা বাশ বৈশিষ্ট্যে আগ্রহী যা আমাকে স্টাডার পুনঃনির্দেশ করতে দেবে। (তবে টেম্প ফাইলের কৌশল নয়)
অ্যান্ড্রু-ডুফ্রেসন

@ অ্যান্ড্রু আমার অর্থ, কমান্ডটি কাজ করার জন্য ডিজাইন করা হয়েছে সেভাবে কাজ করে। এটি আপনি যেভাবে চান ঠিক তেমন কাজ করে না :)
ph

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

2

আপনি স্ট্রিমগুলি অদলবদল করতে পারেন। grepমূলত টার্মিনালে স্ট্যান্ডার্ড আউটপুটে গিয়ে আউটপুট পাওয়ার সময় এটি আপনাকে মূল স্ট্যান্ডার্ড ত্রুটি প্রবাহে সক্ষম করবে :

somecommand 3>&2 2>&1 1>&3- | grep 'pattern'

এটি প্রথমে আউটপুট জন্য একটি নতুন ফাইল বিবরণকারী (3) উন্মুক্ত করে এবং এটি স্ট্যান্ডার্ড ত্রুটি প্রবাহে সেট করে কাজ করে ( 3>&2)। তারপরে আমরা স্ট্যান্ডার্ড ত্রুটিটিকে স্ট্যান্ডার্ড আউটপুট ( 2>&1) এ পুনঃনির্দেশ করি । শেষ অবধি স্ট্যান্ডার্ড আউটপুটটি মূল স্ট্যান্ডার্ড ত্রুটিতে পুনঃনির্দেশিত হয় এবং নতুন ফাইল বিবরণকারী বন্ধ হয় ( 1>&3-)।

আপনার ক্ষেত্রে:

ffmpeg -i 01-Daemon.mp3 3>&2 2>&1 1>&3- | grep -i Duration

এটি পরীক্ষা করা:

$ ( echo "error" >&2; echo "output" ) 3>&2 2>&1 1>&3- | grep "error"
output
error

$ ( echo "error" >&2; echo "output" ) 3>&2 2>&1 1>&3- | grep -v "error"
output

1

আমি rcএই ক্ষেত্রে শেলটি ব্যবহার করতে পছন্দ করি ।

প্রথমে প্যাকেজটি ইনস্টল করুন (এটি 1MB এর চেয়ে কম)।

আপনি কীভাবে গ্রেপ করতে stdoutএবং পাইপ করবেন তার উদাহরণ stderrএটি rc:

find /proc/ >[1] /dev/null |[2] grep task

আপনি বাশকে না রেখে এটি করতে পারেন:

rc -c 'find /proc/ >[1] /dev/null |[2] grep task'

যেমন আপনি লক্ষ্য করেছেন, বাক্য গঠনটি সোজা, যা এটি আমার পছন্দসই সমাধান করে।

পাইপ চরিত্রের ঠিক পরে, আপনি বন্ধনীগুলির মধ্যে পাইপযুক্ত কোন ফাইল বর্ণনাকারী নির্দিষ্ট করতে পারেন।

স্ট্যান্ডার্ড ফাইল বর্ণনাকারী এরূপ হিসাবে নম্বরযুক্ত:

  • 0: স্ট্যান্ডার্ড ইনপুট
  • 1: স্ট্যান্ডার্ড আউটপুট
  • 2: স্ট্যান্ডার্ড ত্রুটি

0

বাশ সাবপ্রোসেস উদাহরণে একটি প্রকরণ:

স্টার্ডার এবং টি স্টেডার দুটি ফাইলে প্রতিধ্বনিত করুন

(>&2 echo -e 'asdf\nfff\n') 2> >(tee some.load.errors | grep 'fff' >&1)

stdout- এ:

fff

some.load.erferences (উদাঃ স্টডার):

asdf
fff

-1

এই আদেশ ব্যবহার করে দেখুন

  • এলোমেলো নাম দিয়ে ফাইল তৈরি করুন
  • ফাইলে আউটপুট প্রেরণ করুন
  • পাইপের জন্য ফাইলের বিষয়বস্তু প্রেরণ করুন
  • , grep

ceva -> কেবলমাত্র একটি পরিবর্তনশীল নাম (ইংরেজি = কিছু)

ceva=$RANDOM$RANDOM$RANDOM; ffmpeg -i qwerty_112_0_0_record.flv 2>$ceva; cat $ceva | grep Duration; rm $ceva;

/tmp/$cevaঅস্থায়ী ফাইলগুলি সহ বর্তমান ডিরেক্টরি লিটারের চেয়ে আমি আরও ভাল ব্যবহার করব - এবং আপনি ধরে নিচ্ছেন যে বর্তমান ডিরেক্টরিটি লিখিতযোগ্য।
রোল্ফ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.