Bash for Oracle DBAs — قسمت 8: Redirection، Pipe و Stream در Bash
در Bash، فرمانها از طریق جریانهای استاندارد با یکدیگر ارتباط برقرار میکنند. درک این جریانها برای Oracle DBAها ضروری است؛ زیرا اسکریپتهای Audit و Remediation اغلب باید نتایج را نمایش دهند، خطاهای مورد انتظار را مخفی کنند، فایلهای پیکربندی بسازند یا خروجی فرمانها را برای پردازشهای بعدی نگه دارند.
سه جریان استاندارد در Bash عبارتاند از:
- stdin — ورودی استاندارد، File Descriptor شماره
0؛ - stdout — خروجی استاندارد، File Descriptor شماره
1؛ - stderr — خروجی خطای استاندارد، File Descriptor شماره
2.
1) خروجی استاندارد: stdout
بهصورت پیشفرض، خروجی عادی فرمانها به stdout فرستاده میشود و معمولاً در Terminal نمایش داده میشود:
echo "Checking Oracle environment..."
hostname
date
در اسکریپت Audit، پیامهای وضعیت با echo و echo -e چاپ میشوند. این پیامها به stdout فرستاده میشوند:
echo "========================================================================="
echo " CIS Requirement: 1.6 System-wide Crypto Policy"
echo "========================================================================="
همین اصل درباره فرمانهای Oracle مانند sqlplus، lsnrctl، srvctl و crsctl نیز برقرار است. خروجی عادی این ابزارها معمولاً در stdout نوشته میشود.
2) خروجی خطای استاندارد: stderr
پیامهای خطا و تشخیصی معمولاً به stderr ارسال میشوند. این جداسازی به اسکریپت اجازه میدهد خروجی موفق فرمان را از خروجی خطا تفکیک کند.
ls /path/that/does/not/exist
این فرمان ممکن است روی stderr خطا تولید کند، حتی اگر stdout خالی باشد. این تفاوت زمانی اهمیت زیادی دارد که خروجی یک فرمان را در متغیر ذخیره میکنید.
3) Redirect کردن stderr با 2>
عملگر 2>، File Descriptor شماره 2 یعنی stderr را Redirect میکند:
command 2>errors.log
در این مثال، خروجی عادی همچنان در Terminal نمایش داده میشود، اما خطاها در فایل errors.log نوشته خواهند شد.
اسکریپت Audit از الگوی زیر استفاده میکند:
CURRENT_POLICY=$(update-crypto-policies --show 2>/dev/null)
در اینجا هر خطایی که توسط update-crypto-policies --show ایجاد شود، دور ریخته میشود. تنها stdout در متغیر CURRENT_POLICY ذخیره خواهد شد.
الگوی مشابهی در فرمان grep دیده میشود:
HARDCODED=$(grep -h -E -i '^\s*(Ciphers|MACs|KexAlgorithms|GSSAPIKexAlgorithms|HostKeyAlgorithms|PubkeyAcceptedKeyTypes)' \
/etc/ssh/sshd_config \
/etc/ssh/sshd_config.d/*.conf \
2>/dev/null)
این کار از نمایش خطاهای مربوط به نبودن فایل یا مشکل دسترسی در خروجی Audit جلوگیری میکند. بااینحال، مخفی کردن خطاها ممکن است اطلاعات تشخیصی مفیدی را پنهان کند؛ بنابراین باید آگاهانه استفاده شود.
4) فایل ویژه /dev/null
/dev/null یک Device ویژه است که هر دادهای را که در آن نوشته شود دور میریزد. وقتی به خروجی یک فرمان نیاز ندارید، استفاده از آن مفید است.
command 2>/dev/null
این فرمان فقط stderr را دور میریزد. برای دور ریختن فقط stdout:
command 1>/dev/null
نوشتن شماره 1 معمولاً اختیاری است:
command >/dev/null
5) Redirect کردن همزمان stdout و stderr
اسکریپت Remediation شامل فرمان زیر است:
if ls /etc/ssh/sshd_config.d/*.conf 1>/dev/null 2>&1; then
...
fi
این فرمان به فهرست فایلهای تولیدشده توسط ls نیازی ندارد. تنها Exit Status آن برای شرط if اهمیت دارد. بنابراین هر دو جریان خروجی دور ریخته میشوند.
ترتیب Redirectها مهم است:
1>/dev/null، خروجی استاندارد را به/dev/nullمیفرستد.2>&1، خروجی خطا را به مقصد فعلی stdout میفرستد.
فرم کوتاهتر زیر از نظر عملی همان نتیجه را دارد:
ls /etc/ssh/sshd_config.d/*.conf >/dev/null 2>&1
اما مراقب ترتیب باشید. حالت زیر متفاوت است:
command 2>&1 >/dev/null
در این حالت، stderr ابتدا به مقصد اصلی stdout متصل میشود و پس از آن بهطور خودکار به /dev/null منتقل نخواهد شد.
6) Redirect کردن stdout به فایل با >
عملگر >، stdout را به یک فایل میفرستد. اگر فایل وجود داشته باشد، محتوای قبلی آن بازنویسی میشود:
echo "Oracle audit started" > audit.log
در اسکریپت Remediation، یک Here Document با Output Redirection ترکیب شده است:
cat <<EOF > /etc/crypto-policies/policies/modules/CIS-SSH.pmod
cipher@ssh = -*CBC -CHACHA20-POLY1305
mac@ssh = -*MD5* -*UMAC-64*
EOF
متن بین <<EOF و EOF به stdin فرمان cat تبدیل میشود. سپس stdout فرمان cat به فایل Policy هدایت خواهد شد.
از آنجا که عملگر > استفاده شده است، فایل موجود بازنویسی میشود. برای افزودن محتوا بهجای بازنویسی از >> استفاده کنید:
echo "Next audit result" >> audit.log
7) Input Redirection با <
Input Redirection یک فایل را به stdin میفرستد:
while IFS= read -r line; do
echo "$line"
done < /etc/oratab
این روش با ارسال فایل بهعنوان آرگومان عادی فرمان تفاوت دارد. فرمان، فایل را از طریق stdin میخواند.
برای Oracle DBAها، این الگو هنگام پردازش /etc/oratab، فهرست Database Instanceها، فایلهای پیکربندی Listener یا گزارشهای تولیدشده توسط Audit مفید است.
8) Pipe چیست؟
Pipe با عملگر |، stdout یک فرمان را به stdin فرمان دیگر متصل میکند:
ps -ef | grep ora_pmon
خروجی ps -ef مستقیماً نمایش داده نمیشود؛ بلکه به ورودی فرمان grep تبدیل میشود.
نمونه دیگر:
df -h | awk '$5+0 > 80 { print }'
این فرمان خروجی استفاده از فضای Disk را به awk میفرستد تا فقط File Systemهایی که بیش از 80 درصد پر هستند نمایش داده شوند.
9) تفاوت Pipe و ||
یکی از تفاوتهای بسیار مهم برای کاربران Bash، تمایز میان | و || است.
|یک Pipe واقعی میان دو فرمان ایجاد میکند.||عملگر منطقی OR است.
اسکریپت Audit یک شرط Logical OR دارد:
if [[ "$CURRENT_POLICY" == *"DEFAULT:NO-SHA1:CIS-SSH"* ||
"$CURRENT_POLICY" == *"FIPS:NO-SHA1:CIS-SSH"* ]]; then
...
fi
این ساختار Pipeline ایجاد نمیکند. مفهوم آن این است: اگر مقایسه اول درست باشد یا مقایسه دوم درست باشد.
10) Pipeline و Exit Status
بهصورت پیشفرض، Exit Status یک Pipeline برابر با Exit Status آخرین فرمان آن است:
command1 | command2
اگر command1 شکست بخورد اما command2 موفق باشد، ممکن است Pipeline همچنان موفق به نظر برسد. برای اسکریپتهای Audit قابلاعتماد، pipefail را فعال کنید:
set -o pipefail
با فعال بودن pipefail، اگر هر فرمانی در Pipeline شکست بخورد، Pipeline نیز شکستخورده محسوب میشود. این یکی از دلایل توصیه الگوی Strict Mode است:
set -euo pipefail
11) ذخیره جداگانه خروجی و خطاها
یک اسکریپت Audit ممکن است نیاز داشته باشد خروجی عادی را نگه دارد و در عین حال خطاها را جداگانه ثبت کند:
output=$(some_command 2>command-errors.log)
status=$?
echo "Output: $output"
echo "Exit status: $status"
این روش اغلب بهتر از ارسال خطاها به /dev/null است؛ زیرا مدیر سیستم میتواند فایل خطا را بعداً بررسی کند.
12) استفاده از tee برای Terminal و Log
فرمان tee، stdin را بهصورت همزمان به stdout و یک فایل کپی میکند:
echo "Audit started" | tee audit.log
پیام هم در Terminal نمایش داده میشود و هم در audit.log نوشته خواهد شد. برای Append کردن بهجای بازنویسی:
echo "Audit completed" | tee -a audit.log
هیچیک از فایلهای audit_07_System_Crypto_Policy.sh و remediate_07_System_Crypto_Policy.sh از tee استفاده نمیکنند. پیامهای وضعیت آنها فقط با echo نمایش داده میشوند و هیچ فایل Logی توسط این اسکریپتها ساخته نمیشود.
13) محدودیت مهم در اسکریپت Remediation
اسکریپت Remediation هر دو Stream را فقط برای فرمان ls، جهت بررسی وجود فایلهای پیکربندی SSH منطبق، Redirect میکند:
ls /etc/ssh/sshd_config.d/*.conf 1>/dev/null 2>&1
فرمانهای اصلی Remediation، شامل sed، update-crypto-policies و systemctl restart sshd، خطاهای خود را Redirect نمیکنند. بنابراین stderr آنها در Terminal قابل مشاهده میماند.
همچنین، بدون set -e یا بررسی صریح Exit Status، ممکن است یک فرمان شکست بخورد اما اسکریپت ادامه پیدا کند و در نهایت پیام موفقیت نمایش دهد. الگوی امنتر به شکل زیر است:
if update-crypto-policies --set DEFAULT:NO-SHA1:CIS-SSH; then
echo "[+] Crypto policy applied successfully."
else
echo "[!] Failed to apply crypto policy." >&2
exit 1
fi
به استفاده از >&2 دقت کنید. این عملگر پیام را به stderr میفرستد، نه stdout؛ بنابراین برای پیام خطا مناسب است.
14) یک نمونه عملی Audit
#!/bin/bash
set -euo pipefail
LOG_FILE="/var/log/oracle_audit.log"
echo "[*] Checking Oracle processes..." | tee -a "$LOG_FILE"
if ps -ef | grep '[o]ra_pmon' | grep -q .; then
echo "[PASS] Oracle instance process found." | tee -a "$LOG_FILE"
else
echo "[FAIL] Oracle instance process not found." | tee -a "$LOG_FILE" >&2
exit 1
fi
این مثال چند مفهوم را با هم ترکیب میکند:
- عملگر Pipe یعنی
|؛ - جستوجوی بیصدا با
grep -q؛ - ثبت Log با
tee -a؛ - ارسال پیام شکست به stderr با
>&2؛ - Strict Mode و مدیریت صریح خطا.
15) جمعبندی
در این مقاله یاد گرفتیم که:
stdin،stdoutوstderrسه Stream استاندارد Bash هستند؛2>، stderr را Redirect میکند؛>، stdout را Redirect کرده و فایل مقصد را بازنویسی میکند؛>>، stdout را به انتهای فایل اضافه میکند؛2>/dev/nullخطاها را دور میریزد؛1>/dev/null 2>&1هر دو جریان stdout و stderr را دور میریزد؛|یک Pipeline واقعی بین فرمانها ایجاد میکند؛||عملگر منطقی OR است و Pipe نیست؛teeمیتواند خروجی را همزمان نمایش دهد و در Log بنویسد؛- مدیریت صریح Exit Status برای اسکریپتهای Remediation ضروری است.
در مقاله بعدی، Pattern Matching، Regular Expression، grep، sed و awk را بررسی خواهیم کرد. این ابزارها در اسکریپتهای Hardening برای بررسی فایلهای پیکربندی، شناسایی تنظیمات ناامن و اعمال تغییرات کنترلشده کاربرد فراوانی دارند.
مقاله قبلی: Bash for Oracle DBAs — قسمت 7: Functionها و استفاده مجدد در Bash
مقاله بعدی: Bash for Oracle DBAs — قسمت 9: Pattern Matching، grep، sed و awk