كيفية استخدام الأمر awk على نظام Linux

على Linux ،  awkهناك دينامو معالجة نصوص سطر الأوامر ، بالإضافة إلى لغة برمجة نصية قوية. إليك مقدمة لبعض أروع ميزاته.

كيف حصلت awk على اسمها

و  awk كان اسمه الأوامر باستخدام الحروف الأولى من ثلاثة أشخاص الذي كتب النص الأصلي في عام 1977: ألفريد آهو، بيتر اينبرغر، وبريان كيرنيغان. كان هؤلاء الرجال الثلاثة من مجموعة AT&T Bell Laboratories Unix Pantheon الأسطورية. مع مساهمات العديد من الآخرين منذ ذلك الحين ، awk استمر في التطور.

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

القواعد والأنماط والإجراءات

awkيعمل على البرامج التي تحتوي على قواعد تتكون من أنماط وإجراءات. يتم تنفيذ الإجراء على النص المطابق للنمط. الأنماط محاطة بأقواس متعرجة ( {}). معًا ، يشكل النمط والإجراء قاعدة. awkالبرنامج بأكمله مرفق بعلامات اقتباس مفردة ( ').

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

هذا هو الناتج القياسي من who:

منظمة الصحة العالمية

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

بشكل افتراضي ، awkيعتبر الحقل سلسلة من الأحرف محاطة بمسافة بيضاء أو بداية سطر أو نهاية سطر. يتم تحديد الحقول بعلامة الدولار ( $) ورقم. إذن ،  $1يمثل الحقل الأول ، الذي سنستخدمه مع print الإجراء لطباعة الحقل الأول.

نكتب ما يلي:

من | awk "{print $ 1}"

awk يطبع الحقل الأول ويتجاهل باقي السطر.

يمكننا طباعة أي عدد نود من الحقول. إذا أضفنا فاصلة كفاصل ،  awkفسنطبع مسافة بين كل حقل.

نكتب ما يلي أيضًا لطباعة وقت تسجيل دخول الشخص (الحقل الرابع):

من | awk "{print $ 1، $ 4}"

هناك نوعان من معرفات الحقول الخاصة. هذه تمثل سطر النص بأكمله والحقل الأخير في سطر النص:

  • 0 $ : يمثل سطر النص بالكامل.
  • $ 1 : يمثل الحقل الأول.
  • 2 دولار : يمثل الحقل الثاني.
  • 7 دولارات : يمثل الحقل السابع.
  • 45 دولارًا : يمثل الحقل 45.
  • $ NF : يرمز إلى "عدد الحقول" ويمثل الحقل الأخير.

سنكتب ما يلي لإحضار ملف نصي صغير يحتوي على اقتباس قصير منسوب إلى دينيس ريتشي:

القط dennis_ritchie.txt

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

نكتب الأمر التالي:

awk "{print $ 1، $ 2، $ NF}" dennis_ritchie.txt

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

إضافة فواصل مجال الإخراج

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

تاريخ
التاريخ | awk "{print $ 2، $ 3، $ 6}"

سنستخدم OFS متغير (فاصل حقل الإخراج) لوضع فاصل بين الشهر واليوم والسنة. لاحظ أننا أدناه نرفق الأمر بعلامات اقتباس مفردة ( ') ، وليس أقواس متعرجة ( {}):

التاريخ | awk 'OFS = "/" {print $ 2، $ 3، $ 6}'
التاريخ | awk 'OFS = "-" {print $ 2، $ 3، $ 6}'

قواعد البداية والنهاية

و BEGINيتم تنفيذ حكم مرة واحدة قبل أي يبدأ تجهيز النصوص. في الواقع ، يتم تنفيذه awk حتى قبل قراءة أي نص. و ENDيتم تنفيذ الحكم بعد اكتمال تجهيز جميع. هل يمكن أن يكون متعددة BEGIN و  ENDقواعد، وأنها سوف تنفيذ في النظام.

بالنسبة لمثالنا على BEGINالقاعدة ، سنطبع الاقتباس بالكامل من dennis_ritchie.txtالملف الذي استخدمناه سابقًا مع عنوان فوقه.

للقيام بذلك ، نكتب هذا الأمر:

awk 'BEGIN {print "Dennis Ritchie"} {print $0}' dennis_ritchie.txt

Note the BEGIN rule has its own set of actions enclosed within its own set of curly braces ({}).

We can use this same technique with the command we used previously to pipe output from who into awk. To do so, we type the following:

who | awk 'BEGIN {print "Active Sessions"} {print $1,$4}'

Input Field Separators

If you want awk to work with text that doesn’t use whitespace to separate fields, you have to tell it which character the text uses as the field separator. For example, the /etc/passwd file uses a colon (:) to separate fields.

We’ll use that file and the -F (separator string) option to tell awk to use the colon (:) as the separator. We type the following to tell awk to print the name of the user account and the home folder:

awk -F: '{print $1,$6}' /etc/passwd

The output contains the name of the user account (or application or daemon name) and the home folder (or the location of the application).

Adding Patterns

If all we’re interested in are regular user accounts, we can include a pattern with our print action to filter out all other entries. Because User ID numbers are equal to, or greater than, 1,000, we can base our filter on that information.

We type the following to execute our print action only when the third field ($3) contains a value of 1,000 or greater:

awk -F: '$3 >= 1000 {print $1,$6}' /etc/passwd

The pattern should immediately precede the action with which it’s associated.

We can use the BEGIN rule to provide a title for our little report. We type the following, using the (\n) notation to insert a newline character into the title string:

awk -F: 'BEGIN {print "User Accounts\n-------------"} $3 >= 1000 {print $1,$6}' /etc/passwd

Patterns are full-fledged regular expressions, and they’re one of the glories of awk.

Let’s say we want to see the universally unique identifiers (UUIDs) of the mounted file systems. If we search through the /etc/fstab file for occurrences of the string “UUID,” it ought to return that information for us.

We use the search pattern “/UUID/” in our command:

awk '/UUID/ {print $0}' /etc/fstab

It finds all occurrences of “UUID” and prints those lines. We actually would’ve gotten the same result without the print action because the default action prints the entire line of text. For clarity, though, it’s often useful to be explicit. When you look through a script or your history file, you’ll be glad you left clues for yourself.

The first line found was a comment line, and although the “UUID” string is in the middle of it, awk still found it. We can tweak the regular expression and tell awk to process only lines that start with “UUID.” To do so, we type the following which includes the start of line token (^):

awk '/^UUID/ {print $0}' /etc/fstab

That’s better! Now, we only see genuine mount instructions. To refine the output even further, we type the following and restrict the display to the first field:

awk '/^UUID/ {print $1}' /etc/fstab

If we had multiple file systems mounted on this machine, we’d get a neat table of their UUIDs.

Built-In Functions

awk has many functions you can call and use in your own programs, both from the command line and in scripts. If you do some digging, you’ll find it very fruitful.

To demonstrate the general technique to call a function, we’ll look at some numeric ones. For example, the following prints the square root of 625:

awk 'BEGIN { print sqrt(625)}'

This command prints the arctangent of 0 (zero) and -1 (which happens to be the mathematical constant, pi):

awk 'BEGIN {print atan2(0, -1)}'

In the following command, we modify the result of the atan2() function before we print it:

awk 'BEGIN {print atan2(0, -1)*100}'

Functions can accept expressions as parameters. For example, here’s a convoluted way to ask for the square root of 25:

awk 'BEGIN { print sqrt((2+3)*5)}'

awk Scripts

If your command line gets complicated, or you develop a routine you know you’ll want to use again, you can transfer your awk command into a script.

In our example script, we’re going to do all of the following:

  • Tell the shell which executable to use to run the script.
  • Prepare awk to use the FS field separator variable to read input text with fields separated by colons (:).
  • Use the OFS output field separator to tell awk to use colons (:) to separate fields in the output.
  • Set a counter to 0 (zero).
  • Set the second field of each line of text to a blank value (it’s always an “x,” so we don’t need to see it).
  • Print the line with the modified second field.
  • Increment the counter.
  • Print the value of the counter.

Our script is shown below.

The BEGIN rule carries out the preparatory steps, while the END rule displays the counter value. The middle rule (which has no name, nor pattern so it matches every line) modifies the second field, prints the line, and increments the counter.

The first line of the script tells the shell which executable to use (awk, in our example) to run the script. It also passes the -f (filename) option to awk, which informs it the text it’s going to process will come from a file. We’ll pass the filename to the script when we run it.

We’ve included the script below as text so you can cut and paste:

#!/usr/bin/awk -f  BEGIN { # set the input and output field separators FS=":" OFS=":" # zero the accounts counter accounts=0 } { # set field 2 to nothing $2="" # print the entire line print $0 # count another account accounts++ } END { # print the results print accounts " accounts.\n" }

Save this in a file called omit.awk. To make the script executable, we type the following using chmod:

chmod +x omit.awk

Now, we’ll run it and pass the /etc/passwd file to the script. This is the file awk will process for us, using the rules within the script:

./omit.awk /etc/passwd

The file is processed and each line is displayed, as shown below.

The “x” entries in the second field were removed, but note the field separators are still present. The lines are counted and the total is given at the bottom of the output.

awk Doesn’t Stand for Awkward

awk doesn’t stand for awkward; it stands for elegance. It’s been described as a processing filter and a report writer. More accurately, it’s both of these, or, rather, a tool you can use for both of these tasks. In just a few lines, awk achieves what requires extensive coding in a traditional language.

That power is harnessed by the simple concept of rules that contain patterns, that select the text to process, and actions that define the processing.