আমি প্রক্রিয়াটির stdout এবং stderr উভয়ই একটি ফাইলে পুনর্নির্দেশ করতে চাই। বাশে আমি কীভাবে এটি করব?
আমি প্রক্রিয়াটির stdout এবং stderr উভয়ই একটি ফাইলে পুনর্নির্দেশ করতে চাই। বাশে আমি কীভাবে এটি করব?
উত্তর:
#!/bin/bash
পরিবর্তে এটি শুরু হয় #!/bin/sh
, কারণ এতে বাশ প্রয়োজন।
do_something 2>&1 | tee -a some_file
এই stdout- এ এবং stdout- এ দ্বারা stderr পুনর্নির্দেশ করতে যাচ্ছে some_file
এবং stdout- এ এটা মুদ্রণ।
do_something &>filename
দেয় না। +1 টি।
Ambiguous output redirect.
কোন ধারণা পাই কেন?
$?
এর প্রস্থান স্থিতিটিকে আর উল্লেখ করে না do_something
, তবে প্রস্থান করার স্থিতি tee
।
আপনি পুনর্নির্দেশ করতে পারেন দ্বারা stderr করার stdout- এ এবং stdout- এ একটি ফাইলে:
some_command >file.log 2>&1
Http://tldp.org/LDP/abs/html/io-redirection.html দেখুন
এই ফর্ম্যাটটি সর্বাধিক জনপ্রিয় &> বিন্যাসের চেয়ে বেশি পছন্দ করা হয় যা কেবল বাশে কাজ করে। বোর্ন শেল এটি ব্যাকগ্রাউন্ডে কমান্ড চালানো হিসাবে ব্যাখ্যা করা যেতে পারে। এছাড়াও ফর্ম্যাটটি আরও পঠনযোগ্য 2 (এটি এসটিডিআরআর) 1 (এসটিডিআউট) এ পুনঃনির্দেশিত।
সম্পাদনা: মন্তব্যে নির্দেশিত অনুসারে অর্ডার পরিবর্তন করা হয়েছে
# Close STDOUT file descriptor
exec 1<&-
# Close STDERR FD
exec 2<&-
# Open STDOUT as $LOG_FILE file for read and write.
exec 1<>$LOG_FILE
# Redirect STDERR to STDOUT
exec 2>&1
echo "This line will appear in $LOG_FILE, not 'on screen'"
এখন, সহজ প্রতিধ্বনি $ LOG_FILE এ লিখবে। ডিমনাইজিংয়ের জন্য দরকারী।
মূল পোস্টটির লেখকের কাছে,
এটি আপনার কী অর্জন করতে হবে তা নির্ভর করে। আপনার স্ক্রিপ্ট থেকে আপনি যে আদেশটি কল করেছেন তার মধ্যে যদি আপনাকে কেবল পুনর্নির্দেশের প্রয়োজন হয় তবে উত্তরগুলি ইতিমধ্যে দেওয়া আছে। আমার বর্তমান স্ক্রিপ্টের মধ্যে পুনর্নির্দেশ সম্পর্কে যা উল্লিখিত কোড স্নিপেটের পরে সমস্ত কমান্ড / বিল্ট-ইনগুলিতে (কাঁটাচামচ সহ) প্রভাবিত করে।
আরেকটি দুর্দান্ত সমাধান হ'ল স্টডি-এরর / আউট এবং লগার বা লগ ফাইল একবারে পুনর্নির্দেশ সম্পর্কে যা "একটি স্ট্রিম" কে দুটি ভাগে যুক্ত করে। এই কার্যকারিতাটি 'টি' কমান্ড দ্বারা সরবরাহ করা হয়েছে যা একাধিক ফাইল বর্ণনাকারী (ফাইল, সকেট, পাইপ, ইত্যাদিতে) একবারে লিখতে / সংযোজন করতে পারে: টি FILE1 ফাইল 2 ...> (সেমিডি 1)> (সেমিডি 2) ...
exec 3>&1 4>&2 1> >(tee >(logger -i -t 'my_script_tag') >&3) 2> >(tee >(logger -i -t 'my_script_tag') >&4)
trap 'cleanup' INT QUIT TERM EXIT
get_pids_of_ppid() {
local ppid="$1"
RETVAL=''
local pids=`ps x -o pid,ppid | awk "\\$2 == \\"$ppid\\" { print \\$1 }"`
RETVAL="$pids"
}
# Needed to kill processes running in background
cleanup() {
local current_pid element
local pids=( "$$" )
running_pids=("${pids[@]}")
while :; do
current_pid="${running_pids[0]}"
[ -z "$current_pid" ] && break
running_pids=("${running_pids[@]:1}")
get_pids_of_ppid $current_pid
local new_pids="$RETVAL"
[ -z "$new_pids" ] && continue
for element in $new_pids; do
running_pids+=("$element")
pids=("$element" "${pids[@]}")
done
done
kill ${pids[@]} 2>/dev/null
}
তো, শুরু থেকেই। ধরে নেওয়া যাক আমাদের / dev / stdout (FD # 1) এবং / dev / stderr (FD # 2) এর সাথে টার্মিনাল সংযুক্ত আছে। অনুশীলনে, এটি একটি পাইপ, সকেট বা যা কিছু হতে পারে।
উপরোক্ত লাইনটি যুক্ত করে একটি স্ক্রিপ্ট চালানোর ফলাফল এবং অতিরিক্ত এটি:
echo "Will end up in STDOUT(terminal) and /var/log/messages"
...নিম্নরূপ:
$ ./my_script
Will end up in STDOUT(terminal) and /var/log/messages
$ tail -n1 /var/log/messages
Sep 23 15:54:03 wks056 my_script_tag[11644]: Will end up in STDOUT(terminal) and /var/log/messages
আপনি যদি আরও পরিষ্কার ছবি দেখতে চান তবে স্ক্রিপ্টে এই 2 টি লাইন যুক্ত করুন:
ls -l /proc/self/fd/
ps xf
bash your_script.sh 1>file.log 2>&1
1>file.log
শেলটি ফাইলটিতে STDOUT প্রেরণের নির্দেশ দেয় file.log
এবং 2>&1
STDERR (ফাইল বর্ণনাকারী 2) কে STDOUT (ফাইল বর্ণনাকারী 1) এ পুনঃনির্দেশ করতে বলে।
দ্রষ্টব্য: অর্ডারটি liw.fi হিসাবে উল্লেখ করেছে, 2>&1 1>file.log
কাজ করে না।
কৌতূহলীভাবে, এটি কাজ করে:
yourcommand &> filename
তবে এটি একটি সিনট্যাক্স ত্রুটি দেয়:
yourcommand &>> filename
syntax error near unexpected token `>'
আপনাকে ব্যবহার করতে হবে:
yourcommand 1>> filename 2>&1
&>>
BASH 4 এ কাজ করছে বলে মনে হচ্ছে:$ echo $BASH_VERSION 4.1.5(1)-release $ (echo to stdout; echo to stderr > /dev/stderr) &>> /dev/null
সংক্ষিপ্ত উত্তর: Command >filename 2>&1
বাCommand &>filename
ব্যাখ্যা:
নিম্নলিখিত কোডটি বিবেচনা করুন যা স্টডআউট শব্দটি "স্টডআউট" এবং স্টার্ডর শব্দ "স্টেডারআর" মুদ্রণ করে।
$ (echo "stdout"; echo "stderror" >&2)
stdout
stderror
নোট করুন যে 'এবং' অপারেটর বাশকে বলে যে 2 একটি ফাইল বর্ণনাকারী (যা স্ট্যাডারকে নির্দেশ করে) এবং কোনও ফাইলের নাম নয়। যদি আমরা '&' বাদ দিয়ে থাকি তবে এই কমান্ডটি stdout
stdout এ মুদ্রণ করবে এবং "2" নামে একটি ফাইল তৈরি করে লিখবেstderror
সেখানে ।
উপরের কোডটি পরীক্ষা করে আপনি নিজেরাই দেখতে পারবেন ঠিক কীভাবে পুনর্নির্দেশ অপারেটররা কাজ করে। উদাহরণস্বরূপ, দুটি বর্ণনাকারীর মধ্যে কোন ফাইলটি পরিবর্তন করে নীচের দুটি লাইনের কোডে 1,2
পুনঃনির্দেশিত করা /dev/null
হয়েছে স্টাডআউট থেকে সমস্ত কিছু এবং যথাক্রমে স্ট্যাডার থেকে সমস্ত কিছু মুছে ফেলা হবে (যা মুদ্রিত রয়েছে)।
$ (echo "stdout"; echo "stderror" >&2) 1>/dev/null
stderror
$ (echo "stdout"; echo "stderror" >&2) 2>/dev/null
stdout
এখন, আমরা নীচের কোডটি কেন আউটপুট তৈরি করে না কেন সমাধানটি ব্যাখ্যা করতে পারি:
(echo "stdout"; echo "stderror" >&2) >/dev/null 2>&1
সত্যই এটি বোঝার জন্য, আমি আপনাকে উচ্চারণের জন্য ফাইলের বিবরণী টেবিলগুলিতে এই ওয়েবপৃষ্ঠাটি পড়ার পরামর্শ দিচ্ছি । ধরে নিই যে আপনি এই পড়াটি করেছেন, আমরা এগিয়ে যেতে পারি। নোট করুন যে বাশ প্রক্রিয়াগুলি বাম থেকে ডানে; এইভাবে বাশ >/dev/null
প্রথমে দেখতে (যা একইরকম 1>/dev/null
) এবং ফাইল বিবরণী 1 সেট করে stdout এর পরিবর্তে / dev / নলের দিকে নির্দেশ করে। এটি সম্পন্ন করার পরে বাশ ডানদিকের দিকে এগিয়ে যায় এবং দেখে 2>&1
। এটি ফাইল বর্ণনাকারী 2 সেট করে ফাইল বর্ণনাকারী 1 হিসাবে একই ফাইলের দিকে নির্দেশ করে (এবং 1 নিজেই বিবরণকারী ফাইল না !!!!) ( এই সংস্থানটি পয়েন্টারে দেখুন)আরও তথ্যের জন্য)) . যেহেতু ফাইল বর্ণনাকারী 1 পয়েন্ট / dev / নাল, এবং ফাইল বিবরণকারী 2 ফাইল ফাইল বর্ণনাকারী 1 হিসাবে একই ফাইলটিতে 2 পয়েন্ট, ফাইল বর্ণনাকারী 2 এখন / dev / নাল পয়েন্ট। সুতরাং উভয় ফাইল বর্ণনাকারী / dev / নালকে নির্দেশ করে এবং এ কারণেই কোনও আউটপুট রেন্ডার করা হয় না।
আপনি যদি ধারণাটি সত্যিই বুঝতে পেরেছেন তা পরীক্ষা করতে, আমরা পুনর্নির্দেশের আদেশটি স্যুইচ করলে আউটপুট অনুমান করার চেষ্টা করুন:
(echo "stdout"; echo "stderror" >&2) 2>&1 >/dev/null
stderror
এখানে যুক্তিটি হ'ল বাম থেকে ডানে বামে মূল্যায়ন করা, ব্যাশ 2> ও 1 দেখায় এবং এইভাবে ফাইল বর্ণনাকারী 2 সেট করে ফাইল বর্ণনাকারী 1, অর্থাৎ স্টাডআউট হিসাবে একই জায়গায় নির্দেশ করে। এরপরে এটি ফাইল ডিস্ট্রিপ্টর 1 সেট করে (মনে রাখবেন </ dev / null = 1> / dev / নাল)> / dev / নালকে নির্দেশ করে, এইভাবে যা মানকে পাঠানো হয় তা মুছে দেয়। এইভাবে আমরা যা বাকী ছিল তা হ'ল সাবসেলের স্ট্যান্ডআউটে পাঠানো হয়নি (প্যারেন্টেসিসের কোড) - "স্টারডার"। মজার বিষয়টি এখানে লক্ষণীয় যে 1 টি স্টডআউটের কেবল পয়েন্টার হলেও পয়েন্টার 2 থেকে 1 এর মাধ্যমে পুনর্নির্দেশ 2>&1
পয়েন্টার 2 -> 1 -> স্টাডাউটের শৃঙ্খলা তৈরি করে না। যদি এটি হয়, 1 / dev / নালকে কোডটি পুনর্নির্দেশের ফলস্বরূপ2>&1 >/dev/null
পয়েন্টার শৃঙ্খলটি 2 -> 1 -> / dev / নাল দিয়ে দেবে, এবং সুতরাং কোডটি কিছুই দেখায় না, আমরা উপরে যা দেখেছি তার বিপরীতে।
পরিশেষে, আমি লক্ষ করব যে এটি করার সহজ উপায় রয়েছে:
এখানে বিভাগ 3...4.৪ থেকে আমরা দেখতে পাচ্ছি যে আমরা অপারেটরটি &>
স্টাডআউট এবং স্টডার উভয়ই পুনর্নির্দেশ করতে ব্যবহার করতে পারি । সুতরাং, যে কোনও কমান্ডের stderr এবং stdout আউটপুট উভয়ই পুনঃনির্দেশ করতে \dev\null
(যা আউটপুট মুছে ফেলে), আমরা কেবল টাইপ করি
$ command &> /dev/null
বা আমার উদাহরণের ক্ষেত্রে:
$ (echo "stdout"; echo "stderror" >&2) &>/dev/null
কী Takeaways:
2>&1 >/dev/null
= হয়! >/dev/null 2>&1
। একটি আউটপুট উত্পন্ন এবং অন্য না!অবশেষে এই দুর্দান্ত সংস্থানগুলি দেখুন:
পুনঃ দিকনির্দেশ উপর ব্যাশ ডকুমেন্টেশন , ফাইল বর্ণনাকারী টেবিল একটি ব্যাখ্যা , ভূমিকা পয়েন্টার থেকে
LOG_FACILITY="local7.notice"
LOG_TOPIC="my-prog-name"
LOG_TOPIC_OUT="$LOG_TOPIC-out[$$]"
LOG_TOPIC_ERR="$LOG_TOPIC-err[$$]"
exec 3>&1 > >(tee -a /dev/fd/3 | logger -p "$LOG_FACILITY" -t "$LOG_TOPIC_OUT" )
exec 2> >(logger -p "$LOG_FACILITY" -t "$LOG_TOPIC_ERR" )
এটি সম্পর্কিত: স্টাইলআউট ও স্ট্ডার সিস্লগ-এ লেখা।
এটি প্রায় কাজ করে, তবে জিন্টেড থেকে নয়; (
আমি একটি সমাধান চেয়েছিলাম stdout প্লাস stderr থেকে আউটপুট একটি লগ ফাইলে লেখা এবং stderr এখনও কনসোলে আছে। সুতরাং আমি টি মাধ্যমে স্ট্যাডার আউটপুট নকল করা প্রয়োজন।
এটিই আমি পেয়েছি সমাধান:
command 3>&1 1>&2 2>&3 1>>logfile | tee -a logfile
পরিস্থিতির জন্য, যখন "পাইপিং" প্রয়োজনীয় হয় আপনি ব্যবহার করতে পারেন:
| &
উদাহরণ স্বরূপ:
echo -ne "15\n100\n"|sort -c |& tee >sort_result.txt
অথবা
TIMEFORMAT=%R;for i in `seq 1 20` ; do time kubectl get pods |grep node >>js.log ; done |& sort -h
এই বাশ-ভিত্তিক সমাধানগুলি STDOUT এবং STDERR আলাদাভাবে পাইপ করতে পারে ("सॉर्ट-সি" এর STDERR থেকে বা STDERR থেকে "সাজানোর -h")।
টগলিং আউটপুট বিটউইন স্টডআউট / স্টার্ডার এবং একটি লগফাইলে প্রক্রিয়াটি স্বয়ংক্রিয় করতে নিম্নলিখিত ফাংশনগুলি ব্যবহার করা যেতে পারে।
#!/bin/bash
#set -x
# global vars
OUTPUTS_REDIRECTED="false"
LOGFILE=/dev/stdout
# "private" function used by redirect_outputs_to_logfile()
function save_standard_outputs {
if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
echo "[ERROR]: ${FUNCNAME[0]}: Cannot save standard outputs because they have been redirected before"
exit 1;
fi
exec 3>&1
exec 4>&2
trap restore_standard_outputs EXIT
}
# Params: $1 => logfile to write to
function redirect_outputs_to_logfile {
if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
echo "[ERROR]: ${FUNCNAME[0]}: Cannot redirect standard outputs because they have been redirected before"
exit 1;
fi
LOGFILE=$1
if [ -z "$LOGFILE" ]; then
echo "[ERROR]: ${FUNCNAME[0]}: logfile empty [$LOGFILE]"
fi
if [ ! -f $LOGFILE ]; then
touch $LOGFILE
fi
if [ ! -f $LOGFILE ]; then
echo "[ERROR]: ${FUNCNAME[0]}: creating logfile [$LOGFILE]"
exit 1
fi
save_standard_outputs
exec 1>>${LOGFILE%.log}.log
exec 2>&1
OUTPUTS_REDIRECTED="true"
}
# "private" function used by save_standard_outputs()
function restore_standard_outputs {
if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
echo "[ERROR]: ${FUNCNAME[0]}: Cannot restore standard outputs because they have NOT been redirected"
exit 1;
fi
exec 1>&- #closes FD 1 (logfile)
exec 2>&- #closes FD 2 (logfile)
exec 2>&4 #restore stderr
exec 1>&3 #restore stdout
OUTPUTS_REDIRECTED="false"
}
স্ক্রিপ্টের ভিতরে ব্যবহারের উদাহরণ:
echo "this goes to stdout"
redirect_outputs_to_logfile /tmp/one.log
echo "this goes to logfile"
restore_standard_outputs
echo "this goes to stdout"
@ ফার্নান্দো-fabreti
আপনি যা করেছেন তাতে যুক্ত করে আমি ফাংশনগুলি সামান্য পরিবর্তন করেছি এবং & - বন্ধটি সরিয়ে ফেলেছি এবং এটি আমার পক্ষে কাজ করে।
function saveStandardOutputs {
if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
exec 3>&1
exec 4>&2
trap restoreStandardOutputs EXIT
else
echo "[ERROR]: ${FUNCNAME[0]}: Cannot save standard outputs because they have been redirected before"
exit 1;
fi
}
# Params: $1 => logfile to write to
function redirectOutputsToLogfile {
if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
LOGFILE=$1
if [ -z "$LOGFILE" ]; then
echo "[ERROR]: ${FUNCNAME[0]}: logfile empty [$LOGFILE]"
fi
if [ ! -f $LOGFILE ]; then
touch $LOGFILE
fi
if [ ! -f $LOGFILE ]; then
echo "[ERROR]: ${FUNCNAME[0]}: creating logfile [$LOGFILE]"
exit 1
fi
saveStandardOutputs
exec 1>>${LOGFILE}
exec 2>&1
OUTPUTS_REDIRECTED="true"
else
echo "[ERROR]: ${FUNCNAME[0]}: Cannot redirect standard outputs because they have been redirected before"
exit 1;
fi
}
function restoreStandardOutputs {
if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
exec 1>&3 #restore stdout
exec 2>&4 #restore stderr
OUTPUTS_REDIRECTED="false"
fi
}
LOGFILE_NAME="tmp/one.log"
OUTPUTS_REDIRECTED="false"
echo "this goes to stdout"
redirectOutputsToLogfile $LOGFILE_NAME
echo "this goes to logfile"
echo "${LOGFILE_NAME}"
restoreStandardOutputs
echo "After restore this goes to stdout"
আপনি যখন পরিস্থিতিগুলিতে exec 2>&1
ব্যাশ ফাংশন ব্যবহার করে পুনরায় লেখার জন্য কোডটি পড়তে সহজ মনে করেন তবে এই জাতীয় জিনিসগুলি ব্যবহার করার বিষয়টি বিবেচনা করুন :
function myfunc(){
[...]
}
myfunc &>mylog.log