পাইপের সাহায্যে "টি" ব্যবহার করার সময় আমি একটি ফাইলে স্টডারার কীভাবে লিখব?


539

টার্মিনালে প্রদর্শন করার সময় কীভাবে teeআউটপুট ( STDOUT) লিখতে হয় তা আমি জানি :aaa.shbbb.out

./aaa.sh | tee bbb.out

আমি এখন STDERRনামক কোনও ফাইলটিতে কীভাবে লিখব ccc.out, যখন এটি প্রদর্শিত হচ্ছে?


2
স্পষ্ট করার জন্য - আপনি কি স্ট্যাডার ফাইলের পাশাপাশি পর্দায় যেতে চান?
চার্লস ডাফি

আমি করেছি, আমি এটি পরিষ্কার করতে আমার পোস্টটি সম্পাদনা করব। আমি বিশ্বাস করি লুনাথের সমাধান যথেষ্ট হবে। সাহায্যের জন্য আপনাদের সবাইকে ধন্যবাদ!
jparanich

উত্তর:


782

আমি ধরে নিচ্ছি আপনি এখনও টার্মিনালে STDERR এবং STDOUT দেখতে চান। আপনি জোশ কেলির উত্তরের জন্য যেতে পারেন, তবে আমি tailপটভূমিতে প্রায় রাখছি যা আপনার লগ ফাইলটিকে খুব হ্যাকিশ এবং ক্লডজিকে আউটপুট করে। আপনি কীভাবে এক্সট্রা এফডি রাখতে এবং পরে এটি মেরে ক্লিনআপ করা প্রয়োজন তা প্রযুক্তিগতভাবে এটি একটিতে করা উচিত তা লক্ষ্য করুন trap '...' EXIT

এই কাজ করতে একটি ভাল উপায় আছে, এবং আপনি ইতিমধ্যে এটি আবিষ্কার করেছি: tee

কেবলমাত্র এটি আপনার স্টাডাউটের জন্য ব্যবহারের পরিবর্তে স্টাডাউটের জন্য একটি টি এবং স্টাডারের জন্য একটি রাখুন। আপনি কিভাবে এটি সম্পাদন করবেন? প্রক্রিয়া প্রতিস্থাপন এবং ফাইল পুনঃনির্দেশ:

command > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)

আসুন এটি বিভক্ত করুন এবং ব্যাখ্যা করুন:

> >(..)

>(...)(প্রক্রিয়া বিকল্প) একটি ফিফো তৈরি করে এবং teeএটি শুনতে দেয় । তারপরে, এটি আপনার প্রথমে শুনছে এমন ফিফোর >STDOUT পুনর্নির্দেশের জন্য (ফাইল পুনর্নির্দেশ) ব্যবহার করে।commandtee

দ্বিতীয়টির জন্য একই জিনিস:

2> >(tee -a stderr.log >&2)

আমরা আবার প্রক্রিয়া প্রতিস্থাপন ব্যবহার করে এমন একটি teeপ্রক্রিয়া তৈরি করি যা এসটিডিআইএন থেকে পড়ে এবং এতে ফেলা হয় stderr.logteeএর ইনপুটটি STDOUT এ ফিরে আসে, তবে যেহেতু এর ইনপুটটি আমাদের STDERR, তাই আমরা teeএর STDOUT পুনরায় আমাদের STDERR এ পুনঃনির্দেশ করতে চাই । তারপরে আমরা ফাইলের পুনর্নির্দেশকে commandফিফোর ইনপুট ( teeএর এসটিডিএন) এ পুনঃনির্দেশ করতে ব্যবহার করি ।

Http://mywiki.wooledge.org/BashGuide/InputAndOutput দেখুন

প্রক্রিয়া প্রতিস্থাপন হ'ল সেই সত্যই সুন্দর জিনিসগুলির মধ্যে একটি যা আপনি bashআপনার শেল হিসাবে বেছে নেওয়ার বোনাস হিসাবে পেয়েছেন sh(পসিক্স বা বোর্ন)।


ইন sh, আপনাকে ম্যানুয়ালি জিনিসগুলি করতে হবে:

out="${TMPDIR:-/tmp}/out.$$" err="${TMPDIR:-/tmp}/err.$$"
mkfifo "$out" "$err"
trap 'rm "$out" "$err"' EXIT
tee -a stdout.log < "$out" &
tee -a stderr.log < "$err" >&2 &
command >"$out" 2>"$err"

5
আমি এটি চেষ্টা করেছি: $ echo "HANG" > >(tee stdout.log) 2> >(tee stderr.log >&2)যা কাজ করে তবে ইনপুটটির জন্য অপেক্ষা করে। এমনটা হওয়ার কোনও সাধারণ কারণ আছে কি?
জাস্টিন

1
@ সিলিফ্রেইক আমি বুঝতে পারি না আপনি কী করতে চান বা সমস্যা যা আপনার হচ্ছে। প্রতিধ্বনি পরীক্ষা; প্রস্থান স্টডআউটে কোনও আউটপুট উত্পাদন করে না, সুতরাং ত্রুটি খালি থাকবে।
lhunath

1
এই মন্তব্যের জন্য ধন্যবাদ; পরে আমার লজিক্যাল ত্রুটিটি কী হয়েছিল তা আমি বের করেছিলাম: যখন ইন্টারেক্টিভ শেল হিসাবে ডাকা হয় তখন ব্যাশ একটি কমান্ড প্রম্পট প্রিন্ট করে এবং স্ট্যাডারে প্রস্থানের প্রতিধ্বনি দেয়। তবে, যদি স্ট্ডার পুনঃনির্দেশিত হয়, তবে ব্যাশটি ডিফল্টরূপে নিরবচ্ছিন্ন হিসাবে শুরু হয়; তুলনা করুন /bin/bash 2> errএবং/bin/bash -i 2> err
সিলি ফ্রিক

15
এবং যারা "দেখছেন বিশ্বাস করছেন", তাদের জন্য একটি দ্রুত পরীক্ষা:(echo "Test Out";>&2 echo "Test Err") > >(tee stdout.log) 2> >(tee stderr.log >&2)
ম্যাথু উইলকক্সসন

2
বাহ ! উত্তম উত্তর: "আসুন এটি আলাদা করুন এবং ব্যাখ্যা করুন" +1
জুলানব

671

কেন সহজভাবে না:

./aaa.sh 2>&1 | tee -a log

এটি কেবল পুনঃনির্দেশ stderrকরে stdout, তাই টি লগ এবং স্ক্রিনে প্রতিধ্বনিত করে। হতে পারে আমি কিছু মিস করছি, কারণ অন্যান্য সমাধানগুলির মধ্যে কিছু সত্যিই জটিল বলে মনে হচ্ছে।

দ্রষ্টব্য: বাশ সংস্করণ 4 যেহেতু আপনি এর |&জন্য সংক্ষেপণ হিসাবে ব্যবহার করতে পারেন 2>&1 |:

./aaa.sh |& tee -a log

85
যদি আপনি উভয় স্টাডাউট (চ্যানেল 1) এবং স্ট্ডার (চ্যানেল 2) উভয়ই একই ফাইলে লগইন করতে চান (এটি একটি স্টাইল এবং স্টেরার উভয়ের মিশ্রণযুক্ত একটি ফাইল) the অন্য, আরও জটিল সমাধান আপনাকে স্টাডআউট এবং স্টেডারকে 2 টি পৃথক ফাইলে (stdout.log এবং stderr.log, যথাক্রমে) আলাদা করতে দেয়। কখনও কখনও এটি গুরুত্বপূর্ণ, কখনও কখনও এটি হয় না।
টাইলার রিক

19
অন্যান্য সমাধানগুলি অনেক ক্ষেত্রে প্রয়োজনের চেয়ে অনেক জটিল। এটি আমার জন্য পুরোপুরি কাজ করে।
ডিস্কিমিনস

13
এই পদ্ধতির সমস্যাটি হ'ল আপনি aaa.sh প্রক্রিয়া থেকে প্রস্থান / স্থিতি কোডটি হারাবেন যা গুরুত্বপূর্ণ হতে পারে (যেমন কোনও মেকফাইলে ব্যবহার করার সময়)। গৃহীত উত্তরের সাথে আপনার এই সমস্যা নেই।
স্টেফান

9
আপনি যদি একীভূত stdout / stderr মনে করেন না তবে ./aaa.sh |& tee aaa.logকাজ করে (ব্যাশে)।
jfs

5
@ স্টেফান আমি বিশ্বাস করি আপনি যদি কমান্ড চেইন set -o pipefailঅনুসরণ করেন ;বা &&আমি ভুল না হয়ে থাকেন তবে আপনি প্রস্থান স্থিতি ধরে রাখতে পারবেন ।
ডেভিড

59

এটি গুগলের মাধ্যমে এটির সন্ধানকারীদের জন্য দরকারী হতে পারে। আপনি যে উদাহরণটি ব্যবহার করতে চান তা কেবল অস্বীকার করুন। অবশ্যই আউটপুট ফাইলগুলির নাম পরিবর্তন করতে দ্বিধা বোধ করবেন।

#!/bin/bash

STATUSFILE=x.out
LOGFILE=x.log

### All output to screen
### Do nothing, this is the default


### All Output to one file, nothing to the screen
#exec > ${LOGFILE} 2>&1


### All output to one file and all output to the screen
#exec > >(tee ${LOGFILE}) 2>&1


### All output to one file, STDOUT to the screen
#exec > >(tee -a ${LOGFILE}) 2> >(tee -a ${LOGFILE} >/dev/null)


### All output to one file, STDERR to the screen
### Note you need both of these lines for this to work
#exec 3>&1
#exec > >(tee -a ${LOGFILE} >/dev/null) 2> >(tee -a ${LOGFILE} >&3)


### STDOUT to STATUSFILE, stderr to LOGFILE, nothing to the screen
#exec > ${STATUSFILE} 2>${LOGFILE}


### STDOUT to STATUSFILE, stderr to LOGFILE and all output to the screen
#exec > >(tee ${STATUSFILE}) 2> >(tee ${LOGFILE} >&2)


### STDOUT to STATUSFILE and screen, STDERR to LOGFILE
#exec > >(tee ${STATUSFILE}) 2>${LOGFILE}


### STDOUT to STATUSFILE, STDERR to LOGFILE and screen
#exec > ${STATUSFILE} 2> >(tee ${LOGFILE} >&2)


echo "This is a test"
ls -l sdgshgswogswghthb_this_file_will_not_exist_so_we_get_output_to_stderr_aronkjegralhfaff
ls -l ${0}

6
না, এবং আমার ধারণা নির্বাহক কিছু ব্যাখ্যা ব্যবহার করতে পারেন। exec >এর অর্থ, কোনও ফাইলের বর্ণনাকারীর লক্ষ্য নির্দিষ্ট গন্তব্যে নিয়ে যাওয়া। ডিফল্টটি 1, সুতরাং, exec > /dev/nullএই অধিবেশন থেকে এখন থেকে stdout এর আউটপুটটিকে / dev / null এ সরান। এই অধিবেশনটির জন্য বর্তমান ফাইল বর্ণনাকারী করে দেখা যায় ls -l /dev/fd/। চেষ্টা করে দেখুন! তারপরে দেখুন যখন আপনি exec 2>/tmp/stderr.log.অতিরিক্ত হিসাবে ইস্যু করবেন তখন কী হয় , এর exec 3>&1অর্থ, 3 নম্বর সহ একটি নতুন ফাইল বর্ণনাকারী তৈরি করুন এবং এটি ফাইল বর্ণনাকারীর টার্গেটে পুনর্নির্দেশ করুন 1 উদাহরণস্বরূপ, কমান্ড জারি হওয়ার পরে লক্ষ্যটি পর্দা ছিল।
ড্রামফায়ার

স্ক্রিন এবং পৃথক ফাইল উভয়ই স্টডআউট এবং স্ট্ডারকে দেখানোর উদাহরণটি দুর্দান্ত !!! অনেক ধন্যবাদ!
মার্সেলো ডি বিক্রয়

21

স্ট্যাডারকে কোনও ফাইলে পুনর্নির্দেশের জন্য, স্ক্রিনে স্টডআউট প্রদর্শন করুন এবং স্টডআউটকে একটি ফাইলে সংরক্ষণ করুন:

./aaa.sh 2> ccc.out | tee ./bbb.out

সম্পাদনা : স্ট্যাডার এবং স্টডআউট উভয়ই স্ক্রিনে প্রদর্শন করতে এবং উভয় কোনও ফাইলে সংরক্ষণ করতে, আপনি ব্যাশের আই / ও পুনঃনির্দেশ ব্যবহার করতে পারেন :

#!/bin/bash

# Create a new file descriptor 4, pointed at the file
# which will receive stderr.
exec 4<>ccc.out

# Also print the contents of this file to screen.
tail -f ccc.out &

# Run the command; tee stdout as normal, and send stderr
# to our file descriptor 4.
./aaa.sh 2>&4 | tee bbb.out

# Clean up: Close file descriptor 4 and kill tail -f.
exec 4>&-
kill %1

1
আমি প্রত্যাশা করি যে ব্যবহারকারী স্টাডার ফাইলটি ছাড়াও তাদের কনসোলটিতে যেতে চান, যদিও এগুলি স্পষ্টভাবে নির্দিষ্ট করা হয়নি।
চার্লস ডাফি

2
আমার আরও পরিষ্কার হওয়া উচিত ছিল, আমি পর্দায় স্টাডারও চাইতাম। আমি এখনও জোশ কেলির সমাধানটি উপভোগ করেছি তবে আমার প্রয়োজনের সাথে মিলে লুনাথের সন্ধান করি। ধন্যবাদ বন্ধুরা!
jparanich

18

অন্য কথায়, আপনি স্টাডাউটকে একটি ফিল্টার ( tee bbb.out) এবং স্টার্ডারকে অন্য ফিল্টারে ( tee ccc.out) এ পাইপ করতে চান । অন্য কমান্ডে স্টডআউট ব্যতীত অন্য কোনও কিছুর পাইপ দেওয়ার কোনও স্ট্যান্ডার্ড উপায় নেই তবে ফাইল বিবরণকারীদের জাগল করে আপনি এটিকে ঘিরে কাজ করতে পারেন।

{ { ./aaa.sh | tee bbb.out; } 2>&1 1>&3 | tee ccc.out; } 3>&1 1>&2

এছাড়াও দেখুন কীভাবে গ্রেড স্ট্যান্ডার্ড ত্রুটি স্ট্রিম (স্টডার)? এবং কখন আপনি কোনও অতিরিক্ত ফাইল বর্ণনাকারী ব্যবহার করবেন?

ব্যাশে (এবং ksh এবং zsh), তবে ড্যাশের মতো অন্য পসিক্স শেলগুলিতে নয়, আপনি প্রক্রিয়া বিকল্প ব্যবহার করতে পারেন :

./aaa.sh > >(tee bbb.out) 2> >(tee ccc.out)

সাবধান! বাশ-এ, এই কমান্ডটি ./aaa.shশেষ হওয়ার সাথে সাথেই ফিরে আসবে , এমনকি যদি teeকমান্ডগুলি এখনও কার্যকর করা হয় (ksh এবং zsh উপ-প্রক্রিয়াগুলির জন্য অপেক্ষা করে না)। আপনি যদি এমন কিছু করেন তবে সমস্যা হতে পারে ./aaa.sh > >(tee bbb.out) 2> >(tee ccc.out); process_logs bbb.out ccc.out। সেক্ষেত্রে ফাইল বর্ণনাকারী জাগলিং বা এর পরিবর্তে ksh / zsh ব্যবহার করুন।


4
এটি একমাত্র উত্তরের মতো বলে মনে হচ্ছে যা স্টাডাউট / স্টার্ডার স্ট্রিমগুলি যেমন রয়েছে তেমন রাখার অনুমতি দেয় (উদাঃ তাদের মার্জ না করে)। খুব সুন্দর!
ব্যবহারকারী 1338062

সবচেয়ে সহজ পদ্ধতির জন্য sh, ক্রোন কাজের জন্য দরকারী, যেখানে প্রক্রিয়া প্রতিস্থাপন উপলব্ধ নয়।
রজার ডিউক

13

যদি ব্যাশ ব্যবহার করা হয়:

# Redirect standard out and standard error separately
% cmd >stdout-redirect 2>stderr-redirect

# Redirect standard error and out together
% cmd >stdout-redirect 2>&1

# Merge standard error with standard out and pipe
% cmd 2>&1 |cmd2

ক্রেডিট (আমার মাথার উপরে থেকে উত্তর না) এখানে যায়: http://www.cygwin.com/ml/cygwin/2003-06/msg00772.html


5

আমার ক্ষেত্রে, একটি স্ক্রিপ্ট কমান্ড চালাচ্ছিল যখন স্টডআউট এবং স্ট্ডার উভয়ই একটি ফাইলে পুনর্নির্দেশ করছিল, এরকম কিছু:

cmd > log 2>&1

আমার এটি আপডেট করার দরকার ছিল যে যখন কোনও ব্যর্থতা হয় তখন ত্রুটি বার্তাগুলির উপর ভিত্তি করে কিছু পদক্ষেপ নেওয়া উচিত। আমি অবশ্যই ডুপটি সরিয়ে 2>&1স্ক্রিপ্ট থেকে স্টডারকে ক্যাপচার করতে পারি তবে ত্রুটি বার্তাগুলি রেফারেন্সের জন্য লগ ফাইলে যাবে না। @ লুনাথের গৃহীত উত্তর একই কাজ করার কথা থাকলেও এটি পুনর্নির্দেশ করে stdoutএবং stderrবিভিন্ন ফাইলগুলিতে, যা আমি চাই তা নয়, তবে এটি আমার সঠিক সমাধানটি সামনে আসতে আমাকে সহায়তা করেছিল:

(cmd 2> >(tee /dev/stderr)) > log

উপরোক্ত সঙ্গে, লগ উভয় একটি কপি থাকবে stdoutএবং stderrআমি ক্যাপচার করতে পারেন stderrসম্পর্কে চিন্তা না করেও আমার স্ক্রিপ্ট থেকে stdout


4

নিম্নলিখিতটি কর্নশেল (ksh) এর জন্য কাজ করবে যেখানে প্রক্রিয়া প্রতিস্থাপন উপলব্ধ নেই,

# create a combined(stdin and stdout) collector
exec 3 <> combined.log

# stream stderr instead of stdout to tee, while draining all stdout to the collector
./aaa.sh 2>&1 1>&3 | tee -a stderr.log 1>&3

# cleanup collector
exec 3>&-

এখানে বাস্তব কৌতুক, এর ক্রম 2>&1 1>&3যা আমাদের ক্ষেত্রে পুননির্দেশনা stderrকরতে stdoutএবং পুননির্দেশনা stdoutবর্ণনাকারী থেকে 3। এই মুহুর্তে stderrএবং stdoutএখনও একত্রিত হয় না।

কার্যত, stderr(যেমন stdin) teeএটি লগইন করা হয় stderr.logএবং বর্ণনাকারী 3 এ পুনর্নির্দেশও করা হয়।

এবং 3বিবরণকারী এটি সর্বদা লগ ইন করে combined.log। সুতরাং combined.logউভয় stdoutএবং থাকে stderr


নিফটি! করুণা যে আন্ডাররেটেড কারণ এটি একটি দুর্দান্ত বিকল্প। আমার কাছে কেএসএইচ, বিটিডব্লিউ :) আছে
রানলেভেল

2

আপনি যদি zsh ব্যবহার করছেন তবে আপনি একাধিক পুনঃনির্দেশগুলি ব্যবহার করতে পারেন, সুতরাং আপনার এমনকি প্রয়োজনও নেই tee:

./cmd 1>&1 2>&2 1>out_file 2>err_file

এখানে আপনি কেবল প্রতিটি স্ট্রিমকে নিজের এবং লক্ষ্য ফাইলে পুনর্নির্দেশ করছেন ।


পুরো উদাহরণ

% (echo "out"; echo "err">/dev/stderr) 1>&1 2>&2 1>/tmp/out_file 2>/tmp/err_file
out
err
% cat /tmp/out_file
out
% cat /tmp/err_file
err

নোট করুন যে এটির জন্য MULTIOSবিকল্পটি সেট করার প্রয়োজন (যা পূর্বনির্ধারিত)।

MULTIOS

একাধিক পুনঃনির্দেশ চেষ্টা করার সময় অন্তর্নিহিত teeগুলি বা সম্পাদন করুন cat( পুনঃনির্দেশ দেখুন )।

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