نحوه اعتبارسنجی سینتکس لینوکس Bash قبل از اجرای آن


ترمینال لینوکس روی صفحه نمایش لپ تاپ در پس زمینه قرمز.
fatmawati achmad zaenuri / Shutterstock

اشتباهات تایپی و تایپی در اسکریپت های لینوکس Bash می تواند کارهای وحشتناکی را هنگام اجرای اسکریپت انجام دهد. در اینجا چند راه برای بررسی نحو اسکریپت ها قبل از اجرای آنها وجود دارد.

اون حشرات مزاحم

نوشتن کد مشکل است. یا به عبارت دقیق تر، نوشتن کدهای بدون خطا و غیر پیش پا افتاده دشوار است. و هر چه تعداد خطوط کد در یک برنامه یا اسکریپت بیشتر باشد، احتمال خطا در آن بیشتر است.

زبانی که به آن برنامه نویسی می کنید تأثیر مستقیمی بر این موضوع دارد. برنامه نویسی در اسمبلی بسیار دشوارتر از برنامه نویسی در C است و برنامه نویسی در C دشوارتر از برنامه نویسی در پایتون است. هر چه سطح زبانی که به آن برنامه نویسی می کنید کمتر باشد، کار بیشتری باید به تنهایی انجام دهید. ممکن است پایتون از رویه‌های جمع‌آوری زباله داخلی لذت ببرد، اما C و کامپایل قطعاً اینطور نیستند.

نوشتن اسکریپت های لینوکس شل چالش های خاص خود را دارد. با استفاده از یک زبان کامپایل شده مانند C، برنامه ای به نام کامپایلر کد منبع شما را می خواند – دستورالعمل های قابل خواندن توسط انسان که در یک فایل متنی می نویسید – و آن را به یک باینری اجرایی تبدیل می کند. یک فایل باینری حاوی دستورالعمل‌های کد ماشینی است که کامپیوتر می‌تواند آن‌ها را بفهمد و روی آن عمل کند.

کامپایلر تنها در صورتی یک فایل باینری تولید می کند که کد منبعی که می خواند و تجزیه و تحلیل می کند با نحو و قوانین دیگر زبان مطابقت داشته باشد. اگر یک فایل را املا کنید کلمه رزرو شده—یک کلمه دستور زبان — یا نام متغیر نادرست، کامپایلر باعث خطا می شود.

به عنوان مثال، برخی از زبان ها اصرار دارند که یک متغیر را قبل از استفاده از آن اعلام کنند، و برخی دیگر چندان ناخوشایند نیستند. اگر زبانی که با آن کار می‌کنید از شما می‌خواهد که متغیرها را اعلام کنید، اما فراموش کرده‌اید که این کار را انجام دهید، کامپایلر یک پیغام خطای متفاوت ارسال می‌کند. اگرچه خطاهای زمان کامپایل آزاردهنده هستند، اما با مشکلات زیادی مواجه می شوند و شما را مجبور می کنند تا به آنها رسیدگی کنید. اما حتی زمانی که برنامه ای دارید که ندارد خطاهای گرامری این بدان معنا نیست که هیچ خطایی در آن وجود ندارد. دور از آن.

اشکالاتی که به نقص های منطقی معمولا تشخیص آن دشوار است. اگر از برنامه خود بخواهید دو و سه را اضافه کند اما واقعاً می خواهید دو و دو اضافه کند، پاسخی را که انتظار داشتید دریافت نخواهید کرد. اما برنامه کاری را که برای آن نوشته شده است انجام می دهد. هیچ مشکلی در ترکیب یا نحو برنامه وجود ندارد. مشکل تو هستی برنامه خوبی نوشتی که اون کاری رو که تو میخوای انجام نمیده.

امتحانش سخته

آزمایش کامل یک برنامه، حتی اگر ساده باشد، زمان زیادی می برد. اجرای چندین بار آن کافی نیست. شما واقعا باید تمام مسیرهای اجرای کد خود را تست کنید تا تمام قسمت های کد بررسی شوند. اگر برنامه درخواست ورودی دارد، باید محدوده کافی از مقادیر ورودی را برای آزمایش همه شرایط – از جمله ورودی غیرقابل قبول – ارائه دهید.

برای زبان‌های سطح بالا، آزمون‌های واحد و تست خودکار کمک می‌کنند تا آزمون جامع به یک تمرین قابل مدیریت تبدیل شود. بنابراین سوال این است که آیا ابزاری وجود دارد که بتوانیم برای نوشتن اسکریپت های بدون خطا در پوسته Bash به ما کمک کنیم؟

پاسخ مثبت است، از جمله خود پوسته bash.

استفاده از Bash برای بررسی نحو

بش -n (noexec) به Bash می‌گوید بدون اجرای اسکریپت، یک اسکریپت را بخواند و آن را برای خطاهای نحوی بررسی کند. بسته به هدف اسکریپت شما، این می تواند ایمن تر از اجرای آن و جستجوی مشکلات باشد.

این متنی است که بررسی خواهیم کرد. این پیچیده نیست، این اساسا مجموعه ای از if فرمولاسیون شماره ای را که نشان دهنده ماه است درخواست می کند و می پذیرد. فیلمنامه تعیین می کند که ماه به کدام فصل تعلق دارد. این بدیهی است که اگر کاربر اصلاً ورودی ارائه نکند، یا اگر ورودی نامعتبر مانند یک حرف به جای عدد ارائه کند، کار نخواهد کرد.

#! /bin/bash

read -p "Enter a month (1 to 12): " month

# did they enter anything?
if [ -z "$month" ]
then
  echo "You must enter a number representing a month."
  exit 1
fi

# is it a valid month?
if (( "$month" < 1 || "$month" > 12)); then
  echo "The month must be a number between 1 and 12."
  exit 0
fi

# is it a Spring month?
if (( "$month" >= 3 && "$month" < 6)); then
  echo "That's a Spring month."
  exit 0
fi

# is it a Summer month?
if (( "$month" >= 6 && "$month" < 9)); then
  echo "That's a Summer month."
  exit 0
fi

# is it an Autumn month?
if (( "$month" >= 9 && "$month" < 12)); then
  echo "That's an Autumn month."
  exit 0
fi

# it must be a Winter month
echo "That's a Winter month."
exit 0

این بخش بررسی می کند که آیا کاربر اصلاً چیزی را وارد کرده است یا خیر. آزمایش می کند که آیا یک فایل $month متغیر تنظیم نشده است.

if [ -z "$month" ]
then
  echo "You must enter a number representing a month."
  exit 1
fi

این بخش بررسی می‌کند که آیا عددی بین ۱ تا ۱۲ وارد کرده‌اند یا خیر. همچنین ورودی نادرست که عدد نیست را جبران می‌کند، زیرا حروف و نمادهای شماره‌گذاری به مقادیر عددی ترجمه نمی‌شوند.

# is it a valid month?
if (( "$month" < 1 || "$month" > 12)); then
  echo "The month must be a number between 1 and 12."
  exit 0
fi

تمام عبارات If دیگر بررسی کنید که آیا مقدار در یک فایل است یا خیر $month متغیر بین دو مقدار است. اگر چنین است، پس ماه متعلق به آن فصل است. به عنوان مثال، اگر ماه وارد شده توسط کاربر ۶، ۷ یا ۸ باشد، پس ماه تابستان است.

# is it a Summer month?
if (( "$month" >= 6 && "$month" < 9)); then
  echo "That's a Summer month."
  exit 0
fi

اگر می خواهید با مثال های ما کار کنید، متن اسکریپت را در یک ویرایشگر کپی و جایگذاری کنید و آن را به عنوان “seasons.sh” ذخیره کنید. سپس اسکریپت را با یک فایل قابل اجرا کنید chmod فرمان:

chmod +x seasons.sh

تنظیم مجوز اجرایی روی اسکریپت

ما می توانیم اسکریپت را از طریق آزمایش کنیم

  • اصلاً هیچ ورودی ارائه نمی کند.
  • ورودی غیر عددی ارائه دهید.
  • یک عدد صحیح خارج از محدوده ۱ تا ۱۲ ارائه دهید.
  • مقادیر عددی را در محدوده ۱ تا ۱۲ ارائه دهید.

در همه موارد اسکریپت را با همین دستور شروع می کنیم. تنها تفاوت ورودی است که کاربر هنگام تبلیغ با اسکریپت ارائه می دهد.

./seasons.sh

یک اسکریپت را با ورودی های معتبر و نامعتبر مختلف تست کنید

به نظر می رسد این کار همانطور که انتظار می رود کار می کند. اجازه دهید Bash نحو اسکریپت ما را بررسی کند. ما این کار را با تماس انجام می دهیم -n (noexec) را انتخاب کنید و نام اسکریپت خود را پاس کنید.

bash -n ./seasons.sh

استفاده از Bash برای آزمایش نحو یک اسکریپت

این یک مورد “بدون خبر خوب” است. بازگرداندن ما در سکوت به خط فرمان، راه bash است که می گوید همه چیز خوب به نظر می رسد. بیایید اسکریپت خود را خراب کنیم و خطا را معرفی کنیم.

حذف خواهیم کرد then از آغاز if مورد

# is it a valid month?
if (( "$month" < 1 || "$month" > 12)); # "then" has been removed
  echo "The month must be a number between 1 and 12."
  exit 0
fi

حالا بیایید ابتدا اسکریپت را بدون ورودی کاربر و سپس بعدا اجرا کنیم.

./seasons.sh

اسکریپت تست با ورودی های نامعتبر و معتبر

اولین باری که اسکریپت اجرا می شود، کاربر مقداری را وارد نمی کند و در نتیجه اسکریپت خاتمه می یابد. پارتیشنی که ما هک کردیم هرگز قابل دسترسی نیست. اسکریپت بدون پیام خطا از طرف Bash به پایان می رسد.

بار دوم که اسکریپت اجرا می شود، کاربر یک مقدار ورودی را ارائه می دهد و اولین شرط if برای اعتبارسنجی ورودی کاربر اجرا می شود. این پیام خطا از Bash را راه اندازی می کند.

توجه داشته باشید که Bash نحو – و هر خط کد – را بررسی می کند زیرا به پسوند اهمیتی نمی دهد منطق از فیلمنامه وقتی Bash اسکریپت را بررسی می کند، کاربر نیازی به وارد کردن شماره ندارد، زیرا اسکریپت کار نمی کند.

مسیرهای مختلف اجرای بالقوه اسکریپت بر نحوه بررسی نحو توسط Bash تأثیر نمی گذارد. Bash به روشی ساده و منظم از بالای اسکریپت به پایین کار می کند و نحو هر خط را بررسی می کند.

ابزار ShellCheck

Linter – به نام ابزار بازرسی کد منبع C از دوران شکوفایی یونیکس – یک ابزار تجزیه و تحلیل کد است که برای شناسایی خطاهای برنامه نویسی، خطاهای سبک و استفاده مشکوک یا مشکوک از یک زبان استفاده می شود. لینترها برای بسیاری از زبان های برنامه نویسی در دسترس هستند و به دلیل پدیداتیک بودن بدنام هستند. هر چیزی که لینتر پیدا می کند اشتباه نیست در خود، اما هر چیزی که توجه شما را جلب کند ممکن است ارزش توجه را داشته باشد.

ShellCheck یک ابزار تجزیه و تحلیل کد برای اسکریپت های پوسته است. مانند نامه ای برای بش عمل می کند.

گمشده هایمان را بگذاریم then کلمه دوباره در اسکریپت ما رزرو شده است، چیز دیگری را امتحان کنید. براکت باز را برداریم[” from the very first if clause.

# did they enter anything?
if -z "$month" ] # براکت باز"[" removed
then
  echo "You must enter a number representing a month."
  exit 1
fi

if we use Bash to check the script it doesn’t find a problem.

bash -n seasons.sh
./seasons.sh

An error message from a script that passed the syntax checking with no detected issues

But when we try to run the script we see an error message. And, despite the error message, the script continues to execute. This is why some bugs are so dangerous. If the actions taken further on in the script rely on valid input from the user, the script’s behavior will be unpredictable. It could potentially put data at risk.

The reason the Bash -n (noexec) option doesn’t find the error in the script is the opening bracket “[” is an external program called [. It isn’t part of Bash. It is a shorthand way of using the test command.

Bash doesn’t check the use of external programs when it is validating a script.

Installing ShellCheck

ShellCheck requires installation. To install it on Ubuntu, type:

sudo apt install shellcheck

Installing shellcheck on Ubuntu

To install ShellCheck on Fedora, use this command. Note that the package name is in mixed case, but when you issue the command in the terminal window it is all in lowercase.

sudo dnf install ShellCheck

Installing shellcheck on Fedora

On Manjaro and similar Arch-based distros, we use pacman:

sudo pacman -S shellcheck

Installing shellcheck on Manjaro

Using ShellCheck

Let’s try running ShellCheck on our script.

shellcheck seasons.sh

Checking a script with ShellCheck

ShellCheck finds the issue and reports it to us, and provides a set of links for further information. If you right-click a link and choose “Open Link” from the context menu that appears, the link will open in your browser.

ShellCheck reporting errors and warnings

ShellCheck also finds another issue, which isn’t as serious. It is reported in green text. This indicates it is a warning, not an out-and-out error.

Let’s correct our error and replace the missing “[.” One bug-fix strategy is to correct the highest priority issues first and work down to the lower priority issues like warnings later.

We replaced the missing “[” and ran ShellCheck once more.

shellcheck seasons.sh

Checking a script a second time with ShellCheck

The only output from ShellCheck refers to our previous warning, so that’s good. We have no high-priority issues needing fixing.

The warning tells us that using the read command without the -r (read as-is) option will cause any backslashes in the input to be treated as escape characters. This is a good example of the type of pedantic output a linter can generate. In our case the user shouldn’t be entering a backslash anyway—we need them to enter a number.

Warnings like this require a judgment call on the part of the programmer. Make the effort to fix it, or leave it as it is? It’s a simple two-second fix. And it’ll stop the warning cluttering up ShellCheck’s output, so we might as well take its advice. We’ll add an “r” to option the flags on the read command, and save the script.

read -pr "Enter a month (1 to 12): " month

Running ShellCheck once more gives us a clean bill of health.

No errors or warnings reported by ShellCheck

ShellCheck Is Your Friend

ShellCheck can detect, report, and advise on a whole range of issues. Check out their gallery of bad code, which shows how many types of problems it can detect.

It’s free, fast, and takes a lot of the pain out of writing shell scripts. What’s not to like?