مقدمة
خلال عمل المستخدم على الطرفية باستخدام سطر الأوامر؛ قد يحتاج أحيانا لنسخ المخرجات لاستخدامها لاحقا أو مشاركتها مع الآخرين لطلب المساعدة. من الأدوات التي تسهل العملية السابقة أداة ‘tee‘. سنتعرف في هذا الدليل على كيفية استخدام هذا الأمر مع أمثلة مبسطة.
ما أداة tee؟
أداة سطر أوامر على أنظمة جنو/لينكس، يتمثل عملها في حفظ أو كتابة مخرجات أمر معين (منفذٍّ على الطرفية) في مِلَفّ أو عدة ملفات (حسب حاجة المستخدم) لاستخدامه لاحقا لأغراض مختلفة.
طريقة استخدام الأمر tee
الصيغة
tee [OPTION] [FILE]
أمثلة على استخدام الأداة
1. كتابة المخرجات على مِلَفّ واحد
أبسط عمل للأمر tee هو كتابة المخرجات دون أي خيارات في مِلَفّ واحد.
الصيغة
command | tee filename
ملاحظة: في سطر الأوامر يستخدم زر | أو كما يسمى بالإنجليزية ‘pipe’ أو ‘vertical bar’ لإعادة توجيه مخرجات أمر معين وتحويلها لمدخلات أمر آخر.
مثال
في هذا المثال سنستخدم الأمر ls لعرض محتوى مجلد معين بطريقة سهلة القراءة ومرتبة من الأكبر إلى الأصغر حسب الحجم. ثم نستخدم الأمر tee لحفظ مخرجات الأمر ls السابق في مِلَفّ نصي.
ls -shS | tee list_of_files.txt
[linuxaw@linuxaw Ubuntu Flavors]$ ls -shS | tee list_of_files.txt total 24G 4.1G ubuntustudio-21.10-dvd-amd64.iso 3.6G ubuntukylin-21.10-desktop-amd64.iso 3.2G ubuntu-mate-21.10-desktop-amd64.iso 3.2G kubuntu-21.10-desktop-amd64.iso 3.0G ubuntu-budgie-21.10-desktop-amd64.iso 3.0G ubuntu-21.10-desktop-amd64.iso 2.0G xubuntu-21.10-desktop-amd64.iso 2.0G lubuntu-21.10-desktop-amd64.iso
نستطيع الآن تصفح محتوى المِلَفّ عبر محرر النصوص أو مباشرة باستخدام الأمر cat في نفس جلسة الطرفية.
cat list_of_files.txt
[linuxaw@linuxaw Ubuntu Flavors]$ cat list_of_files.txt total 24G 4.1G ubuntustudio-21.10-dvd-amd64.iso 3.6G ubuntukylin-21.10-desktop-amd64.iso 3.2G ubuntu-mate-21.10-desktop-amd64.iso 3.2G kubuntu-21.10-desktop-amd64.iso 3.0G ubuntu-budgie-21.10-desktop-amd64.iso 3.0G ubuntu-21.10-desktop-amd64.iso 2.0G xubuntu-21.10-desktop-amd64.iso 2.0G lubuntu-21.10-desktop-amd64.iso
2. كتابة المخرجات على أكثر من مِلَفّ
يمكن استخدام الأمر tee لحفظ المخرجات على عدة ملفات مختلفة بنفس المحتوى كنسخ احتياطية مثلا. يتم ذلك بكتابة أسماء الملفات متتالية والفصل بينها بمسافة (زر Space).
الصيغة
command | tee file_name_1 file_name_2 file_name_3
مثال
سنستخدم في هذا المثال الأمر df لعرض استهلاك مساحة قسم المنزل.
df -h /home | tee home_usage_1.txt home_usage_2.txt home_usage_3.txt
[linuxaw@linuxaw ~]$ df -h /home | tee home_usage_1.txt home_usage_2.txt home_usage_3.txt Filesystem Size Used Avail Use% Mounted on /dev/sda11 45G 20G 23G 47% /home
هذه مخرجات عرض الملفات الثلاثة المنشأة
cat home_usage_1.txt home_usage_2.txt home_usage_3.txt
[linuxaw@linuxaw ~]$ cat home_usage_1.txt home_usage_2.txt home_usage_3.txt Filesystem Size Used Avail Use% Mounted on /dev/sda11 45G 20G 23G 47% /home Filesystem Size Used Avail Use% Mounted on /dev/sda11 45G 20G 23G 47% /home Filesystem Size Used Avail Use% Mounted on /dev/sda11 45G 20G 23G 47% /home
3. كتابة المخرجات في نهاية المِلَفّ
عند كتابة اسم المِلَفّ بعد الأمر tee مباشرة دون خيارات (options) كما في الأمثلة السابقة فإن الأداة تستبدل محتوى المِلَفّ إن كان موجودا. لإضافة المخرجات لنهاية المِلَفّ دون استبداله نستخدم خِيار a- بعد الأمر tee.
الصيغة
command | tee -a filename
command | tee --append filename
مثال
سنفرض في مثالنا هذا أننا سنستخدم الأمر free لعرض استهلاك الذاكرة العشوائية كل مدة زمنية نحددها بأنفسنا من أجل المقارنة، لذلك ننفذ الأمر
free -h | tee memory_usage.txt
[linuxaw@linuxaw ~]$ free -h | tee memory_usage.txt total used free shared buff/cache available Mem: 7.3Gi 1.1Gi 3.2Gi 155Mi 2.9Gi 5.7Gi Swap: 8.4Gi 6.0Mi 8.4Gi
بعد مدة معينة من الاستخدام نعيد تنفيذ الأمر لكن هذه المرة مع خِيار a- للاحتفاظ بالمخرجات الأولى من أجل المقارنة.
free -h | tee -a memory_usage.txt
[linuxaw@linuxaw ~]$ free -h | tee -a memory_usage.txt total used free shared buff/cache available Mem: 7.3Gi 1.6Gi 2.6Gi 244Mi 3.0Gi 5.1Gi Swap: 8.4Gi 6.0Mi 8.4Gi
عند عرض محتوى المِلَفّ المنشأ تكون النتيجة كالآتي
cat memory_usage.txt
[linuxaw@linuxaw ~]$ cat memory_usage.txt total used free shared buff/cache available Mem: 7.3Gi 1.1Gi 3.2Gi 155Mi 2.9Gi 5.7Gi Swap: 8.4Gi 6.0Mi 8.4Gi total used free shared buff/cache available Mem: 7.3Gi 1.6Gi 2.6Gi 244Mi 3.0Gi 5.1Gi Swap: 8.4Gi 6.0Mi 8.4Gi
4. كتابة المخرجات مع إخفاء ظهورها
يمكن للمستخدم كتابة مخرجات أمر معين على مِلَفّ دون إظهار هذه المخرجات في شاشة الطرفية. يتم ذلك باستخدام dev/null/ بعد الأمر tee.
الصيغة
command | tee filename > /dev/null
مثال
سنستخدم في هذا المثال الأمر uname لعرض المعلومات عن نظام التشغيل.
uname -a | tee system_info.txt > /dev/null
[linuxaw@linuxaw ~]$ uname -a | tee system_info.txt > /dev/null [linuxaw@linuxaw ~]$
نلاحظ في المثال الماضي أنه لا تظهر أي مخرجات على شاشة الطرفية. للتحقق من مخرجات الأمر المكتوبة في المِلَفّ نستخدم الأداة cat.
cat system_info.txt
[linuxaw@linuxaw ~]$ cat system_info.txt Linux linuxaw 5.13.8-pclos1 #1 SMP Wed Aug 4 12:43:06 CDT 2021 x86_64 x86_64 x86_64 GNU/Linux
5. كتابة المخرجات مع تجاهل المقاطعة
عند استخدام خِيار i- مع الأمر tee فإن ذلك يُمَكِّن الأداة من تجاهل المقاطعة التي تحدث للعملية أو التي يجريها المستخدم بالضغط على اختصار Ctrl+C في لوحة المفاتيح. وبذلك يخرج الأمر tee بشكل آمن بعد كتابة المخرجات بشكل صحيح.
الصيغة
command | tee -i filename
command | tee --ignore-interrupts filename
مثال
نستخدم هنا الأداة ping التي تفحص اتصال الجهاز بجهاز آخر وتظهر نتائج الفحص. سنفحص الاتصال مع خادم محرك البحث Searx. ولمعرفة الفرق ننفذ الأمر أولا دون استخدام خِيار تجاهل المقاطعة. ثم نضغط على Ctrl+C خلال العملية لمقاطعتها.
ping searx.me | tee ping_stats.txt
[linuxaw@linuxaw ~]$ ping searx.me | tee ping_stats.txt PING searx.me (194.150.168.104) 56(84) bytes of data. 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=1 ttl=49 time=62.7 ms 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=2 ttl=49 time=53.2 ms 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=3 ttl=49 time=53.8 ms 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=4 ttl=49 time=63.7 ms ^C [linuxaw@linuxaw ~]$
نعرض الآن مخرجات الملف
cat ping_stats.txt
[linuxaw@linuxaw ~]$ cat ping_stats.txt PING searx.me (194.150.168.104) 56(84) bytes of data. 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=1 ttl=49 time=62.7 ms 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=2 ttl=49 time=53.2 ms 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=3 ttl=49 time=53.8 ms 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=4 ttl=49 time=63.7 ms
نعيد الكرة لكن مع استخدام خِيار تجاهل المقاطعة
ping searx.me | tee -i ping_stats.txt
[linuxaw@linuxaw ~]$ ping searx.me | tee -i ping_stats.txt PING searx.me (194.150.168.104) 56(84) bytes of data. 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=1 ttl=49 time=55.0 ms 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=2 ttl=49 time=62.3 ms 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=3 ttl=49 time=63.6 ms 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=4 ttl=49 time=59.1 ms ^C --- searx.me ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3004ms rtt min/avg/max/mdev = 55.000/60.035/63.656/3.344 ms [linuxaw@linuxaw ~]$
نعيد عرض مخرجات الملف
cat ping_stats.txt
[linuxaw@linuxaw ~]$ cat ping_stats.txt PING searx.me (194.150.168.104) 56(84) bytes of data. 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=1 ttl=49 time=55.0 ms 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=2 ttl=49 time=62.3 ms 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=3 ttl=49 time=63.6 ms 64 bytes from 104.168.150.194.in-addr.arpa (194.150.168.104): icmp_req=4 ttl=49 time=59.1 ms --- searx.me ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3004ms rtt min/avg/max/mdev = 55.000/60.035/63.656/3.344 ms
نلاحظ أن الفرق بين النتيجتين أن عدم استخدام خِيار i- يؤدي لعدم حفظ ملخص الإحصائيات آخر المخرجات وهو ما حصلنا عليه في المثال الثاني بعد استخدام الخِيار.
6. توجيه مخرجات أمر معين نحو أمر آخر
يمكن استخدام علامة ‘pipe‘ لجعل المخرجات التي يكتبها الأمر tee مدخلات لأمر آخر يُنَفَّذُ بعده.
الصيغة
command_1 | tee -i filename | command_2
مثال
نستخدم هنا الأمر ls لعرض محتويات مجلد معين ثم نستخدم الأمر grep للبحث عن كلمة معينة في أسماء الملفات الموجودة
ls | tee list_of_files.txt | grep "xubuntu"
[linuxaw@linuxaw Ubuntu Flavors]$ ls | tee list_of_files.txt | grep "xubuntu"
xubuntu-21.10-desktop-amd64.iso
7. اِستخدام الأمر tee مع أداة sudo
يحتاج التعديل على ملفات النظام إلى الصلاحيات الإدارية. يستعمل المستخدمون لهذه المهام محررات النصوص من الطرفية أو بواسطة الواجهة الرسومية. يمكن أيضا استخدام الأمر tee مع الأمر sudo للكتابة على مِلَفّ يتطلب هذه الصلاحيات.
الصيغة
عند الكتابة على الملف
text | sudo tee filename
عند الإضافة لنهاية الملف
text | sudo tee -a filename
مثال
سنفرض أننا نريد تغيير اسم المضيف (hostname) في مِلَفّ hostname الموجود في مسار etc. نستخدم الأمر echo لطباعة الاسم الجديد ثم نستخدم tee لكتابته في المِلَفّ المذكور.
echo "linuxaw-host" | sudo tee /etc/hostname
[linuxaw@linuxaw ~]$ echo "linuxaw-host" | sudo tee /etc/hostname [sudo] password for linuxaw: linuxaw-host
بتنفيذنا للأمر السابق يستبدل tee المِلَفّ القديم (اِسم المضيف القديم) ويعوضه بالملف الجديد (اِسم المضيف الجديد).
cat /etc/hostname
[linuxaw@linuxaw ~]$ cat /etc/hostname linuxaw-host
الحصول على المساعدة لاستخدام tee
يمكن الوصول لدليل استخدام الأداة والحصول على المساعدة بواسطة الأمرين اﻵتيين
tee --help
man tee
خاتمة
بقراءتك لهذا الدليل تكون قد تعرفت إلى كيفية استخدام الأداة tee بشكل أساسي. ومن المحتمل أنك أدركت أيضا أهميتها وفائدتها في حفظ المخرجات لاستخدامها لاحقا. يمكنك مطالعة تصنيف أوامر الطرفية لدروس أكثر حول استخدام سطر الأوامر على أنظمة جنو/لينكس.