13 أداة لمعالجة النصوص قائمة على الصدفة

في ما يلي جزء من كتاب مستقبلي ، "الأدوات الأساسية والممارسات لمطور برامج مبتدئ" ، كتبه بالتزار روبرول وإتيان برود . يجب أن يساعد الكتاب في تثقيف جيل الشباب من المطورين. سيغطي موضوعات مثل إتقان وحدة التحكم ، والإعداد والعمل بكفاءة في أمر الأوامر ، وإصدار التعليمات البرمجية باستخدام gitأساسيات SQL ، وأدوات مثل Make، jqوالتعبيرات العادية ، وأساسيات الشبكات ، بالإضافة إلى أفضل الممارسات لتطوير البرامج والتعاون. يعمل المؤلفون حاليًا بجد في هذا المشروع ويدعون الجميع للمشاركة في القائمة البريدية .

المحتوى



معالجة نص شل


أحد الأسباب التي تجعل من أمر الأوامر أداة لا تقدر بثمن هو العدد الكبير من أوامر معالجة الكلمات والقدرة على دمجها بسهولة في خط الأنابيب ، وإنشاء قوالب معالجة معقدة. تجعل هذه الأوامر العديد من المهام تافهة لتحليل النص والبيانات ، وتحويل البيانات بين التنسيقات المختلفة ، وتصفية السلاسل ، وما إلى ذلك.

عند العمل مع البيانات النصية ، فإن المبدأ الأساسي هو تقسيم أي مشكلة معقدة إلى العديد من المشاكل الصغيرة - وحل كل منها منهم باستخدام أداة متخصصة.

اجعل كل برنامج يقوم بشيء جيد - أساسيات فلسفة يونكس

قد تبدو الأمثلة الواردة في هذا الفصل بعيدة المنال قليلاً للوهلة الأولى ، ولكن يتم ذلك عن قصد. تم تصميم كل أداة لحل مشكلة صغيرة واحدة. ومع ذلك ، عندما يتم دمجها ، فإنها تصبح قوية للغاية.

سنلقي نظرة على بعض أوامر معالجة النصوص الأكثر شيوعًا وفائدة في shell الأوامر وسنعرض سير العمل الحقيقي الذي يربطها ببعضها البعض. أقترح النظر إلى مانا هذه الفرق لمعرفة النطاق الكامل للإمكانيات المتاحة لك.

يتوفر ملف CSV كمثال على الإنترنت . يمكنك تنزيله للتحقق من المواد.

قط


يتم catاستخدام الأمر لتجميع قائمة بملف واحد أو أكثر وعرض محتوياتها على الشاشة.

$ cat Documents/readme
Thanks again for reading this book!
I hope you're following so far!

$ cat Documents/computers
Computers are not intelligent
They're just fast at making dumb things.

$ cat Documents/readme Documents/computers
Thanks again for reading this book!
I hope you are following so far!

Computers are not intelligent
They're just fast at making dumb things.

رئيس


headيطبع الأسطر n الأولى في الملف. يمكن أن يكون هذا مفيدًا جدًا للبحث في ملف بهيكل وتنسيق غير معروفين دون ملء وحدة التحكم بأكملها بمجموعة من النصوص.

$ head -n 2 metadata.csv
metric_name,metric_type,interval,unit_name,per_unit_name,description,orientation,integration,short_name
mysql.galera.wsrep_cluster_size,gauge,,node,,The current number of nodes in the Galera cluster.,0,mysql,galera cluster size

إذا -nلم يكن محددًا ، headفسيتم طباعة الأسطر العشرة الأولى من الملف أو دفق الإدخال المحدد.

ذيل


tail- تناظري head، فقط يعرض آخر خطوط n في الملف.

$ tail -n 1 metadata.csv
mysql.performance.queries,gauge,,query,second,The rate of queries.,0,mysql,queries

إذا كنت ترغب في طباعة جميع الأسطر الموجودة بعد السطر n (بما في ذلك) ، يمكنك استخدام الوسيطة -n +n.

$ tail -n +42 metadata.csv
mysql.replication.slaves_connected,gauge,,,,Number of slaves connected to a replication master.,0,mysql,slaves connected
mysql.performance.queries,gauge,,query,second,The rate of queries.,0,mysql,queries

يوجد 43 سطرًا في ملفنا ، لذلك tail -n +42لا ينتج عنه سوى الخطين 42 و 43 منه.

إذا -nلم يتم تحديد المعلمة ، tailفستخرج الأسطر العشرة الأخيرة في الملف المحدد أو دفق الإدخال.

tail -fأو tail --followعرض الأسطر الأخيرة في الملف وكل سطر جديد أثناء كتابتها إلى الملف. هذا مفيد جدًا لعرض النشاط في الوقت الفعلي ، على سبيل المثال ، ما يتم تسجيله في سجلات خادم الويب ، إلخ.

مرحاض


wc(عدد الكلمات) يعرض عدد الأحرف ( -c) أو الكلمات ( -w) أو الأسطر ( -l) في الملف أو الدفق المحدد.

$ wc -l metadata.csv
43  metadata.csv
$ wc -w metadata.csv
405 metadata.csv
$ wc -c metadata.csv
5094 metadata.csv

بشكل افتراضي ، يتم عرض كل ما سبق.

$ wc metadata.csv
43     405    5094 metadata.csv

إذا تم توجيه البيانات النصية أو إعادة توجيهها إلى stdin، فسيتم عرض العداد فقط.

$ cat metadata.csv | wc
43     405    5094
$ cat metadata.csv | wc -l
43
$ wc -w < metadata.csv
405

جريب


grep- هذا عبارة عن سلاسل ترشيح سكين سويسرية وفقًا لنمط معين.

على سبيل المثال ، يمكننا العثور على كل تكرارات كلمة mutex في ملف.

$ grep mutex metadata.csv
mysql.innodb.mutex_os_waits,gauge,,event,second,The rate of mutex OS waits.,0,mysql,mutex os waits
mysql.innodb.mutex_spin_rounds,gauge,,event,second,The rate of mutex spin rounds.,0,mysql,mutex spin rounds
mysql.innodb.mutex_spin_waits,gauge,,event,second,The rate of mutex spin waits.,0,mysql,mutex spin waits

grepيمكن معالجة الملفات المحددة كوسيطات أو دفق من النص الذي تم تمريره إليها stdin. وبالتالي ، يمكننا ربط عدة أوامر grepلزيادة ترشيح النص. في المثال التالي ، نقوم بتصفية الخطوط الموجودة في ملفنا metadata.csvللعثور على السطور التي تحتوي على كلاً من mutex و OS .

$ grep mutex metadata.csv | grep OS
mysql.innodb.mutex_os_waits,gauge,,event,second,The rate of mutex OS waits.,0,mysql,mutex os waits

دعونا نفكر في بعض الخيارات grepوسلوكهم.

grep -vإجراء مطابقة عكسية: سلاسل الفلاتر التي لا تتطابق مع نمط الوسيطة.

$ grep -v gauge metadata.csv
metric_name,metric_type,interval,unit_name,per_unit_name,description,orientation,integration,short_name

grep -iتنفيذ مطابقة غير حساسة لحالة الأحرف. grep -i osيعثر المثال التالي على كل من نظام التشغيل ونظام التشغيل .

$ grep -i os metadata.csv
mysql.innodb.mutex_os_waits,gauge,,event,second,The rate of mutex OS waits.,0,mysql,mutex os waits
mysql.innodb.os_log_fsyncs,gauge,,write,second,The rate of fsync writes to the log file.,0,mysql,log fsyncs

grep -l يسرد الملفات التي تحتوي على تطابق.

$ grep -l mysql metadata.csv
metadata.csv

grep -cيحسب الفريق عدد مرات العثور على عينة.

$ grep -c select metadata.csv
3

grep -r يبحث بشكل متكرر عن الملفات الموجودة في دليل العمل الحالي وجميع الأدلة الفرعية الخاصة به.

$ grep -r are ~/Documents
/home/br/Documents/computers:Computers are not intelligent
/home/br/Documents/readme:I hope you are following so far!

grep -w يظهر فقط مطابقة الكلمات الكاملة.

$ grep follow ~/Documents/readme
I hope you are following so far!
$ grep -w follow ~/Documents/readme
$

يقطع


cutيستخرج جزءًا من الملف (أو ، كالمعتاد ، دفق الإدخال). يقوم الأمر بتعريف فاصل الحقل (الذي يفصل بين الأعمدة) باستخدام الخيار -d، وأرقام الأعمدة المراد استردادها باستخدام الخيار -f.

على سبيل المثال ، يسترجع الأمر التالي العمود الأول من الأسطر الخمسة الأخيرة من ملف CSV.

$ tail -n 5 metadata.csv | cut -d , -f 1
mysql.performance.user_time
mysql.replication.seconds_behind_master
mysql.replication.slave_running
mysql.replication.slaves_connected
mysql.performance.queries

نظرًا لأننا نتعامل مع CSV ، يتم فصل الأعمدة بفاصلة ، والخيار مسؤول عن استرداد العمود الأول -f 1.

يمكنك تحديد العمودين الأول والثاني باستخدام الخيار -f 1,2.

$ tail -n 5 metadata.csv | cut -d , -f 1,2
mysql.performance.user_time,gauge
mysql.replication.seconds_behind_master,gauge
mysql.replication.slave_running,gauge
mysql.replication.slaves_connected,gauge
mysql.performance.queries,gauge

معجون


paste يدمج ملفين مختلفين معًا في ملف متعدد الأعمدة.

$ cat ingredients
eggs
milk
butter
tomatoes
$ cat prices
1$
1.99$
1.50$
2$/kg
$ paste ingredients prices
eggs    1$
milk    1.99$
butter  1.50$
tomatoes    2$/kg

بشكل افتراضي ، pasteيستخدم محدد علامة جدولة ، ولكن يمكن تغييره باستخدام المعلمة -d.

$ paste ingredients prices -d:
eggs:1$
milk:1.99$
butter:1.50$
tomatoes:2$/kg

حالة استخدام شائعة أخرى paste هي دمج جميع الأسطر في دفق أو ملف باستخدام المحدد المحدد ، باستخدام مزيج من -sو -d.

$ paste -s -d, ingredients
eggs,milk,butter,tomatoes

إذا تم تحديد معلمة كملف إدخال -، فسيتم قراءتها بدلاً من ذلك stdin.

$ cat ingredients | paste -s -d, -
eggs,milk,butter,tomatoes

فرز


يقوم الأمر sortبالفعل بفرز البيانات (في الملف المحدد أو دفق الإدخال).

$ cat ingredients
eggs
milk
butter
tomatoes
salt
$ sort ingredients
butter
eggs
milk
salt
tomatoes

sort -r ينفذ الفرز العكسي.

$ sort -r ingredients
tomatoes
salt
milk
eggs
butter

sort -n فرز الحقول حسب قيمتها الحسابية.

$ cat numbers
0
2
1
10
3
$ sort numbers
0
1
10
2
3
$ sort -n numbers
0
1
2
3
10

uniq


uniq يكتشف ويصفى الخطوط المتطابقة المجاورة في الملف المحدد أو دفق الإدخال.

$ cat duplicates
and one
and one
and two
and one
and two
and one, two, three
$ uniq duplicates
and one
and two
and one
and two
and one, two, three

نظرًا لأنها تقوم uniqبتصفية الخطوط المجاورة فقط ، فقد تظل النسخ المكررة في بياناتنا. لتصفية جميع الأسطر من ملف ما ، يجب عليك أولاً فرز محتوياته.

$ sort duplicates | uniq
and one
and one, two, three
and two

uniq -c في بداية كل سطر يُدرج عدد تكراراته.

$ sort duplicates | uniq -c
   3 and one
   1 and one, two, three
   2 and two

uniq -u يعرض سلاسل فريدة فقط.

$ sort duplicates | uniq -u
and one, two, three

ملحوظة. uniqمفيد بشكل خاص مع الفرز ، لأن خط الأنابيب | sort | uniqيسمح لك بحذف جميع الأسطر المكررة في ملف أو دفق.

اووك


awk- هذه ليست أكثر من مجرد أداة لمعالجة الكلمات: في الواقع ، لديها لغة برمجة كاملة . ما هو جيد awk حقًا هو تقسيم الملفات إلى أعمدة ، وهو يفعل ذلك بتألق خاص عندما تختلط المسافات وعلامات التبويب في الملفات.

$ cat -t multi-columns
John Smith    Doctor^ITardis
Sarah-James Smith^I    Companion^ILondon
Rose Tyler   Companion^ILondon

ملحوظة. cat -tيعرض علامات التبويب باسم ^I.

كما ترى ، يتم فصل الأعمدة إما بمسافات أو بعلامات جدولة ، وليس دائمًا بنفس عدد المسافات. cutإنه عديم الفائدة هنا لأنه يعمل مع حرف فاصل واحد فقط. ولكن awkمن السهل التعامل مع مثل هذا الملف.

awk '{ print $n }'يعرض العمود التاسع في النص.

$ cat multi-columns | awk '{ print $1 }'
John
Sarah-James
Rose
$ cat multi-columns | awk '{ print $3 }'
Doctor
Companion
Companion
$ cat multi-columns | awk '{ print $1,$2 }'
John Smith
Sarah-James Smith
Rose Tyler

awkعلى الرغم من أنها قادرة على أكثر من ذلك بكثير ، فإن إخراج المتحدثين هو على الأرجح 99 ٪ من حالات الاستخدام في حالتي الشخصية.

ملحوظة. { print $NF }يعرض العمود الأخير على التوالي.

tr


trلتقف على ترجمة . يستبدل هذا الأمر شخصية بأخرى. يعمل مع إما الأحرف أو فئات الأحرف مثل الأحرف الصغيرة ، والكتابة ، والمسافات ، والأبجدية الرقمية ، وما إلى ذلك.

في الإدخال القياسي ، فإنه tr <char1> <char2>يستبدل جميع تكرارات <char1> بـ <char2>.

$ echo "Computers are fast" | tr a A
computers Are fAst

trيمكن أن تترجم فئات الأحرف باستخدام الترميز [:class:]. يتم وصف قائمة كاملة بالفصول المتاحة على صفحة الدليل tr، ولكن يتم توضيح بعضها هنا.

[:space:]يمثل جميع أنواع المساحات ، من المساحات البسيطة إلى علامات التبويب أو الأسطر الجديدة.

$ echo "computers are fast" | tr '[:space:]' ','
computers,are,fast,%

جميع الأحرف ، مثل المسافات ، مفصولة بفواصل. يرجى ملاحظة أن الحرف %في نهاية الإخراج يشير إلى عدم وجود خط إنهاء جديد. في الواقع ، يتم تحويل هذه الشخصية أيضًا إلى فاصلة.

[:lower:]يمثل جميع الأحرف الصغيرة ، [:upper:] وجميع الأحرف الكبيرة. وهكذا ، يصبح التحول بينهما تافها.

$ echo "computers are fast" | tr '[:lower:]' '[:upper:]'
COMPUTERS ARE FAST
$ echo "COMPUTERS ARE FAST" | tr '[:upper:]' '[:lower:]'
computers are fast

tr -c SET1 SET2يحول أي حرف غير مضمن في SET1 إلى أحرف في SET2. في المثال التالي ، يتم استبدال جميع الأحرف بمسافات.

$ echo "computers are fast" | tr -c '[aeiouy]' ' '
 o  u e   a e  a

tr -dيحذف الأحرف المحددة ، لكن لا يحل محلها. هذا هو المكافئ tr <char> ''.

$ echo "Computers Are Fast" | tr -d '[:lower:]'
C A F

trيمكن أيضًا استبدال نطاقات الأحرف ، على سبيل المثال ، جميع الأحرف بين a و e أو جميع الأرقام بين 1 و 8 ، باستخدام الترميز s-e، حيث s يكون حرف البداية ، e والنهاية.

$ echo "computers are fast" | tr 'a-e' 'x'
xomputxrs xrx fxst
$ echo "5uch l337 5p34k" | tr '1-4' 'x'
5uch lxx7 5pxxk

tr -s string1يضغط الأمر كل تكرارات الأحرف المتعددة string1في واحد. أحد الاستخدامات الأكثر فائدة tr -sهو استبدال عدة مسافات متتالية بأخرى.

$ echo "Computers         are       fast" | tr -s ' '
Computers are fast

يطوى


يقوم الأمر foldبطي جميع خطوط الإدخال إلى العرض المحدد. على سبيل المثال ، قد يكون من المفيد التأكد من ملاءمة النص للشاشات الصغيرة. لذا ، fold -w nتكدس سلاسل من الأحرف n العرض.

$ cat ~/Documents/readme | fold -w 16
Thanks again for
 reading this bo
ok!
I hope you're fo
llowing so far!

سيقوم الأمر fold -sبقطع الأسطر فقط على أحرف المسافات. يمكن دمجه مع السلسلة السابقة لقصر السلسلة على عدد الأحرف المحدد.

Thanks again
for reading
this book!
I hope you're
following so
far!

تافه


sedهو محرر دفق غير تفاعلي يتم استخدامه لتحويل النص في دفق الإدخال سطراً بسطر. كمدخل ، إما ملف أو ، أو stdinعند الإخراج ، إما ملف أو stdout.

ويمكن أن تشمل أوامر محرر واحد أو أكثر من عناوين ، و ظيفة، و المعلمات . وبالتالي ، فإن الأوامر هي كما يلي:

[address[,address]]function[arguments]

على الرغم من أنه sedيؤدي العديد من الوظائف ، إلا أننا سننظر فقط في استبدال النص كواحدة من أكثر حالات الاستخدام شيوعًا.

استبدال النص


أمر الاستبدال sedكالتالي:

s/PATTERN/REPLACEMENT/[options]

مثال : استبدال المثيل الأول لكلمة في كل سطر في ملف:

$ cat hello
hello hello
hello world!
hi
$ cat hello | sed 's/hello/Hey I just met you/'
Hey I just met you hello
Hey I just met you world
hi

نرى أنه في السطر الأول يتم استبدال المثيل الأول فقط hello. لاستبدال كل التكرارات helloفي جميع الأسطر ، يمكنك استخدام الخيار g(يعني عالمي ).

$ cat hello | sed 's/hello/Hey I just met you/g'
Hey I just met you Hey I just met you
Hey I just met you world
hi

sedيسمح لك باستخدام أي محددات باستثناء /، مما يحسن بشكل خاص إمكانية القراءة إذا كانت هناك خطوط مائلة في وسيطات الأمر نفسها.

$ cat hello | sed 's@hello@Hey I just met you@g'
Hey I just met you Hey I just met you
Hey I just met you world
hi

يخبر العنوان المحرر عن أي خط أو نطاق من الأسطر لإجراء الاستبدال.

$ cat hello | sed '1s/hello/Hey I just met you/g'
Hey I just met you hello
hello world
hi
$ cat hello | sed '2s/hello/Hey I just met you/g'
hello hello
Hey I just met you  world
hi

العنوان 1يشير إلى استبدال helloعلى Hey I just met youفي السطر الأول. يمكننا تحديد نطاق العناوين في التدوين <start>,<end>، حيث <end>يمكن أن يكون إما رقم السطر أو $، أي السطر الأخير في الملف.

$ cat hello | sed '1,2s/hello/Hey I just met you/g'
Hey I just met you Hey I just met you
Hey I just met you world
hi
$ cat hello | sed '2,3s/hello/Hey I just met you/g'
hello hello
Hey I just met you world
hi
$ cat hello | sed '2,$s/hello/Hey I just met you/g'
hello hello
Hey I just met you world
hi

بشكل افتراضي ، sedينتج النتيجة بنفسه stdout، ولكن يمكنه أيضًا تحرير الملف الأصلي باستخدام الخيار -i.

$ sed -i '' 's/hello/Bonjour/' sed-data
$ cat sed-data
Bonjour hello
Bonjour world
hi

ملحوظة. على Linux ، ما يكفي -i. ولكن على macOS ، يختلف سلوك الأمر قليلاً ، لذا -iتحتاج إلى الإضافة بعد ذلك مباشرة ''.

أمثلة حقيقية


تصفية CSV باستخدام grep و awk


$ grep -w gauge metadata.csv | awk -F, '{ if ($4 == "query") { print $1, "per", $5 } }'
mysql.performance.com_delete per second
mysql.performance.com_delete_multi per second
mysql.performance.com_insert per second
mysql.performance.com_insert_select per second
mysql.performance.com_replace_select per second
mysql.performance.com_select per second
mysql.performance.com_update per second
mysql.performance.com_update_multi per second
mysql.performance.questions per second
mysql.performance.slow_queries per second
mysql.performance.queries per second

في هذا المثال grep، يقوم الملف metadata.csvأولاً بتصفية الخطوط التي تحتوي على الكلمة gauge، ثم تلك التي تحتوي على queryالعمود الرابع ، ويعرض اسم المقياس (العمود الأول) بالقيمة المقابلة per_unit_name(العمود الخامس).

يعرض عنوان IPv4 المرتبط بواجهة الشبكة


$ ifconfig en0 | grep inet | grep -v inet6 | awk '{ print $2 }'
192.168.0.38

ifconfig <interface name>يعرض الأمر معلومات عن واجهة الشبكة المحددة. على سبيل المثال:

en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    ether 19:64:92:de:20:ba
    inet6 fe80::8a3:a1cb:56ae:7c7c%en0 prefixlen 64 secured scopeid 0x7
    inet 192.168.0.38 netmask 0xffffff00 broadcast 192.168.0.255
    nd6 options=201<PERFORMNUD,DAD>
    media: autoselect
    status: active

ثم قم بالجري من grepأجل inetأن ينتج خطين من المراسلات.

$ ifconfig en0 | grep inet
    inet6 fe80::8a3:a1cb:56ae:7c7c%en0 prefixlen 64 secured scopeid 0x7
    inet 192.168.0.38 netmask 0xffffff00 broadcast 192.168.0.255

ثم باستخدام grep -vاستبعاد الخط مع ipv6.

$ ifconfig en0 | grep inet | grep -v inet6
inet 192.168.0.38 netmask 0xffffff00 broadcast 192.168.0.255

أخيرًا ، بمساعدة ، awkنطلب العمود الثاني في هذا الصف: هذا هو عنوان IPv4 المرتبط بواجهة شبكتنا en0.

$ ifconfig en0 | grep inet | grep -v inet6 | awk '{ print $2 }'
192.168.0.38

ملحوظة. وأنا عرضت على استبدال grep inet | grep -v inet6هذا الفريق يعتمد عليه awk:

$ ifconfig en0 | awk ' $1 == "inet" { print $2 }'
192.168.0.38

وهي أقصر وتستهدف بشكل خاص IPv4 مع الشرط $1 == "inet".

استرجاع قيمة من ملف التكوين


$ grep 'editor =' ~/.gitconfig  | cut -d = -f2 | sed 's/ //g'
/usr/bin/vim

في ملف تكوين git الخاص بالمستخدم الحالي ، ابحث عن القيمة editor =واقطع الحرف =واستخرج العمود الثاني واحذف جميع المسافات حوله.

$ grep 'editor =' ~/.gitconfig
     editor = /usr/bin/vim
$ grep 'editor =' ~/.gitconfig  | cut -d'=' -f2
 /usr/bin/vim
$ grep 'editor =' ~/.gitconfig  | cut -d'=' -f2 | sed 's/ //'
/usr/bin/vim

استخرج عناوين IP من ملف السجل


يبحث الكود الحقيقي التالي عن رسالة في سجل قاعدة البيانات Too many connections from(متبوعًا بعنوان IP) ويعرض المتسللين العشرة الرئيسيين.

$ grep 'Too many connections from' db.log | \
  awk '{ print $12 }' | \
  sed 's@/@@' | \
  sort | \
  uniq -c | \
  sort -rn | \
  head -n 10 | \
  awk '{ print $2 }'
   10.11.112.108
   10.11.111.70
   10.11.97.57
   10.11.109.72
   10.11.116.156
   10.11.100.221
   10.11.96.242
   10.11.81.68
   10.11.99.112
   10.11.107.120

دعونا نرى ما يفعله خط الأنابيب هذا. أولاً ، كيف يبدو السطر في السجل.

$ grep "Too many connections from" db.log | head -n 1
2020-01-01 08:02:37,617 [myid:1] - WARN  [NIOServerCxn.Factory:1.2.3.4/1.2.3.4:2181:NIOServerCnxnFactory@193] - Too many connections from /10.11.112.108 - max is 60

ثم awk '{ print $12 }'يستخرج عنوان IP من السلسلة.

$ grep "Too many connections from" db.log | awk '{ print $12 }'
/10.11.112.108
...

sed 's@/@@'يحذف الأمر الخط المائل الأولي.

$ grep "Too many connections from" db.log | awk '{ print $12 }' | sed 's@/@@'
10.11.112.108
...

ملحوظة. كما رأينا سابقًا ، sedيمكنك استخدام أي فاصل فيه. على الرغم من أنه يُستخدم عادةً كفاصل /، فإننا هنا نستبدل هذا الحرف المعين ، والذي سيضعف قليلاً من إمكانية قراءة تعبير الاستبدال.

sed 's/\///'

sort | uniq -c فرز عناوين IP بترتيب معجمي ، ثم إزالة التكرارات ، وإضافة عدد الإدخالات قبل كل عنوان IP.

$ grep 'Too many connections from' db.log | \
  awk '{ print $12 }' | \
  sed 's@/@@' | \
  sort | \
  uniq -c
   1379 10.11.100.221
   1213 10.11.103.168
   1138 10.11.105.177
    946 10.11.106.213
   1211 10.11.106.4
   1326 10.11.107.120
   ...

sort -rn | head -n 10يفرز الخطوط حسب عدد التكرارات ، رقميًا وبترتيب عكسي ، بحيث يتم عرض المخالفين الرئيسيين أولاً ، يتم عرض 10 خطوط. awk { print $2 }يسترجع الأمر الأخير عناوين IP بأنفسهم.

$ grep 'Too many connections from' db.log | \
  awk '{ print $12 }' | \
  sed 's@/@@' | \
  sort | \
  uniq -c | \
  sort -rn | \
  head -n 10 | \
  awk '{ print $2 }'
  10.11.112.108
  10.11.111.70
  10.11.97.57
  10.11.109.72
  10.11.116.156
  10.11.100.221
  10.11.96.242
  10.11.81.68
  10.11.99.112
  10.11.107.120

إعادة تسمية دالة في ملف المصدر


تخيل أننا نعمل على مشروع ونود إعادة تسمية الوظيفة غير المسماة (أو فئة ، متغير ، وما إلى ذلك) في الملف المصدر. يمكنك القيام بذلك باستخدام أمر sed -iيستبدل مباشرة في الملف الأصلي.

$ cat izk/utils.py
def bool_from_str(s):
    if s.isdigit():
        return int(s) == 1
    return s.lower() in ['yes', 'true', 'y']

$ sed -i 's/def bool_from_str/def is_affirmative/' izk/utils.py
$ cat izk/utils.py
def is_affirmative(s):
    if s.isdigit():
        return int(s) == 1
    return s.lower() in ['yes', 'true', 'y']

ملحوظة. على نظام macOS ، sed -iاستخدم بدلاً من ذلك sed -i ''.

ومع ذلك ، أعدنا تسمية الوظيفة في الملف الأصلي فقط. سيؤدي ذلك إلى فصل الاستيراد bool_from_strفي أي ملف آخر حيث لم تعد هذه الوظيفة محددة. نحتاج إلى إيجاد طريقة لإعادة التسمية bool_from_strخلال مشروعنا. يمكن تحقيق ذلك باستخدام الأوامر grep، sedوكذلك الحلقات forأو باستخدام xargs.

تعميق: دورات forوxargs


لاستبدال جميع الأحداث في مشروعنا bool_from_str، يجب عليك أولاً العثور عليها بشكل متكرر grep -r.

$ grep -r bool_from_str .
./tests/test_utils.py:from izk.utils import bool_from_str
./tests/test_utils.py:def test_bool_from_str(s, expected):
./tests/test_utils.py:    assert bool_from_str(s) == expected
./izk/utils.py:def bool_from_str(s):
./izk/prompt.py:from .utils import bool_from_str
./izk/prompt.py:                    default = bool_from_str(os.environ[envvar])

نظرًا لأننا مهتمون فقط بالملفات ذات التطابقات ، يجب عليك أيضًا استخدام الخيار -l/--files-with-matches:

-l, --files-with-matches
        Only the names of files containing selected lines are written to standard out-
        put.  grep will only search a file until a match has been found, making
        searches potentially less expensive.  Pathnames are listed once per file
        searched.  If the standard input is searched, the string ``(standard input)''
        is written.

$ grep -r --files-with-matches bool_from_str .
./tests/test_utils.py
./izk/utils.py
./izk/prompt.py

ثم يمكننا استخدام الأمر xargsلتنفيذ إجراءات من كل سطر من المخرجات (أي جميع الملفات التي تحتوي على الخط bool_from_str).

$ grep -r --files-with-matches bool_from_str . | \
  xargs -n 1 sed -i 's/bool_from_str/is_affirmative/'

-n 1يشير الخيار إلى أنه يجب على كل سطر في الإخراج تنفيذ أمر منفصل sed.

ثم يتم تنفيذ الأوامر التالية:

$ sed -i 's/bool_from_str/is_affirmative/' ./tests/test_utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/prompt.py

إذا كان الأمر الذي تتصل به xargs(في حالتنا sed) يدعم وسيطات متعددة ، فيجب عليك تجاهل الحجة من -n 1أجل الأداء.

grep -r --files-with-matches bool_from_str . | xargs sed -i 's/bool_from_str/is_affirmative/'

سيتم تنفيذ هذا الأمر بعد ذلك

$ sed -i 's/bool_from_str/is_affirmative/' ./tests/test_utils.py ./izk/utils.py ./izk/prompt.py

ملحوظة. من الملخص sedفي الصفحة الرئيسية ، يمكن ملاحظة أن الفريق يمكن أن يأخذ العديد من الحجج.

SYNOPSIS
     sed [-Ealn] command [file ...]
     sed [-Ealn] [-e command] [-f command_file] [-i extension] [file ...]

في الواقع ، كما رأينا في الفصل السابق ، فهذا file ...يعني قبول العديد من الحجج ، وهي أسماء الملفات.

نرى أن الاستبدالات تتم لجميع الأحداث bool_from_str.

$ grep -r is_affirmative .
./tests/test_utils.py:from izk.utils import is_affirmative
./tests/test_utils.py:def test_is_affirmative(s, expected):
./tests/test_utils.py:    assert is_affirmative(s) == expected
./izk/utils.py:def is_affirmative(s):
./izk/prompt.py:from .utils import is_affirmative
./izk/prompt.py:                    default = is_affirmative(os.environ[envvar])

كما يحدث في كثير من الأحيان ، هناك عدة طرق لتحقيق نفس النتيجة. بدلاً من ذلك ، xargsيمكننا استخدام حلقات forللتكرار عبر الخطوط في القائمة واتخاذ إجراء بشأن كل عنصر. تحتوي هذه الحلقات على بناء الجملة التالي:

for item in list; do
    command $item
done

إذا كنا التفاف قيادتنا grepفي $()، ثم قذيفة سيتم تنفيذ ذلك في المستوى الفرعي ، وبعد ذلك يتم تكرار النتيجة التي في حلقة for.

$ for file in $(grep -r --files-with-matches bool_from_str .); do
  sed -i 's/bool_from_str/is_affirmative/' $file
done

سيتم تنفيذ هذا الأمر

$ sed -i 's/bool_from_str/is_affirmative/' ./tests/test_utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/prompt.py

forتبدو بنية الحلقة أكثر وضوحًا بالنسبة لي من ذلك xargs، ولكن هذا الأخير يمكنه تنفيذ الأوامر بالتوازي باستخدام المعلمات -P n، حيث nيمثل الحد الأقصى لعدد الأوامر المتوازية التي يتم تنفيذها في نفس الوقت ، والتي يمكن أن تعطي مكاسب في الأداء.

ملخص


تفتح كل هذه الأدوات عالماً كاملاً من الاحتمالات ، لأنها تسمح لك باستخراج البيانات وتحويلها ، وإنشاء خطوط أنابيب كاملة من فرق ربما لم يكن القصد منها العمل معًا. يؤدي كل منهم وظيفة صغيرة نسبيًا (الفرز sortوالجمع catوالفلاتر grepوالتحرير sedوالقطع cutوما إلى ذلك).

يمكن اختزال أي مهمة تتضمن نصًا إلى مجموعة من المهام الأصغر حجمًا ، حيث يقوم كل منها بإجراء بسيط وينقل مخرجاته إلى المهمة التالية.

على سبيل المثال ، إذا أردنا معرفة عدد عناوين IP الفريدة الموجودة في ملف السجل ، وبالتالي تظهر عناوين IP هذه دائمًا في العمود نفسه ، فيمكننا تشغيل تسلسل الأوامر التالي:

  • grep سلاسل تتطابق مع نمط السلاسل بعناوين IP
  • ابحث عن العمود بعنوان IP ، استخرجه بـ awk
  • فرز قائمة عناوين IP باستخدام sort
  • القضاء على التكرارات المجاورة uniq
  • احسب عدد الأسطر (أي عناوين IP الفريدة) باستخدام wc -l

نظرًا لوجود العديد من أدوات معالجة الكلمات الأصلية والجهات الخارجية ، فهناك أيضًا العديد من الطرق لحل أي مشكلة.

كانت الأمثلة في هذه المقالة بعيدة المنال ، ولكن أقترح عليك قراءة المقالة الرائعة "أدوات سطر الأوامر يمكن أن تكون أسرع 235 مرة من مجموعة Hadoop الخاصة بك" للحصول على فكرة عن مدى فائدة هذه الأوامر وفعاليتها حقًا وما هي المشاكل الحقيقية يمكنهم أن يقرروا.

ماذا بعد


  1. احسب عدد الملفات والأدلة الموجودة في دليل منزلك.
  2. .
  3. , .
  4. . .



« » (Essential Tools and Practices for the Aspiring Software Developer) , . , , , , git, SQL, Make, jq , , .

, !

All Articles