خانه / آموزش‌ها / آموزش ماژول shlex در پایتون (تحلیل دستورات شل)

آموزش ماژول shlex در پایتون (تحلیل دستورات شل)

🐍 HomeOfPython
|
📅 1404/10/18

سطح مقدماتی (Beginner Level)

ماژول shlex (مخفف Shell Lexical analysis) یکی از ماژول‌های استاندارد و بسیار کاربردی پایتون است. هدف اصلی این ماژول، تجزیه و تحلیل رشته‌های متنی (String) شبیه به روشی است که Shell یونیکس (مانند Bash) آن‌ها را می‌خواند.

اگر شما قصد دارید برنامه‌ای بنویسید که دستورات ورودی کاربر را پردازش کند، یا می‌خواهید رشته‌ای را برای استفاده در ماژول subprocess آماده کنید، shlex ابزار اصلی شماست.

۱. چرا از split() معمولی استفاده نکنیم؟

بسیاری از مبتدیان برای جدا کردن کلمات یک دستور از متد str.split() استفاده می‌کنند. اما این روش زمانی که در متن "فاصله" (Space) داخل کوتیشن داشته باشیم، شکست می‌خورد.

ماژول shlex هوشمند است و می‌داند که فضاهای خالی داخل کوتیشن‌ها نباید جدا شوند.

مثال اول: مشکل متد split معمولی (Code Snippet)

در این مثال می‌بینید که منطق ساده پایتون برای دستورات پیچیده کافی نیست.

python
# Static Code: This logic is flawed for shell commands
command = 'git commit -m "Fixing bugs"'
parts = command.split()
# Result: ['git', 'commit', '-m', '"Fixing', 'bugs"'] 
# اشتباه است! پیام کامیت دو تکه شده است.

مثال دوم: استفاده صحیح از shlex.split (Interactive)

در این مثال، همان دستور بالا را با shlex پردازش می‌کنیم تا نتیجه صحیح را ببینید.

Python

مثال سوم: مدیریت کاراکترهای خاص (Interactive)

shlex به صورت خودکار از کاراکترهای Escape (مثل \) نیز پشتیبانی می‌کند.

Python

۲. خواندن دستورات از فایل یا ورودی

گاهی اوقات ورودی شما یک رشته ساده نیست، بلکه جریانی از داده‌هاست. shlex می‌تواند مستقیماً روی ورودی‌ها کار کند.

مثال اول: ساختار کلی (Static)

این کد نشان می‌دهد چگونه می‌توان یک شیء shlex ساخت، اما بدون ورودی اجرا نمی‌شود.

python
import shlex

def create_parser(input_text):
    lexer = shlex.shlex(input_text)
    return lexer

مثال دوم: خواندن توکن به توکن (Interactive)

در اینجا ما یک رشته را به عنوان یک فایل شبیه‌سازی می‌کنیم و توکن‌های آن را یکی‌یکی می‌خوانیم.

Python

سطح پیشرفته (Professional Level)

در سطح حرفه‌ای، shlex فقط برای جدا کردن رشته‌ها نیست؛ بلکه ابزاری حیاتی برای امنیت سایبری (جلوگیری از تزریق کد) و ساخت پارسرهای سفارشی است. همچنین در نسخه‌های جدید پایتون قابلیت‌های معکوس (تبدیل لیست به رشته شل) اضافه شده است.

۱. امنیت و جلوگیری از Shell Injection با shlex.quote

زمانی که می‌خواهید یک نام فایل یا ورودی کاربر را در یک دستور Shell اجرا کنید، اگر کاربر ورودی مخربی مثل ; rm -rf / وارد کند، سیستم شما در خطر است. تابع shlex.quote() (در پایتون ۳.۳+) ورودی را به گونه‌ای تغییر می‌دهد که در Shell فقط به عنوان یک "رشته" شناخته شود، نه دستور اجرایی.

مثال اول: مفهوم ناامن بودن (Static)

کد زیر نشان می‌دهد چگونه عدم استفاده از quote می‌تواند خطرناک باشد.

python
import os

filename = "file; rm -rf /"
# DANGEROUS: This would delete files!
# os.system(f"ls -l {filename}") 

مثال دوم: ایمن‌سازی ورودی (Interactive)

در این مثال می‌بینیم که shlex.quote چگونه ورودی خطرناک را خنثی می‌کند.

Python

۲. بازسازی دستور با shlex.join

این متد (که در پایتون ۳.۸ اضافه شد) دقیقاً برعکس split عمل می‌کند. یعنی یک لیست از آرگومان‌ها را می‌گیرد و یک رشته واحد و ایمن برای اجرا در Shell تولید می‌کند.

مثال اول: ترکیب لیست (Interactive)

Python

مثال دوم: کاربرد عملی در Docker (Interactive)

فرض کنید می‌خواهید یک دستور docker exec بسازید.

Python

۳. شخصی‌سازی کلاس shlex (Custom Parser)

کلاس shlex بسیار منعطف است. شما می‌توانید تعریف کنید چه کاراکترهایی به عنوان کامنت (#)، چه کاراکترهایی به عنوان جداکننده و چه کاراکترهایی به عنوان فضای خالی در نظر گرفته شوند. این برای ساخت زبان‌های پیکربندی کوچک (mini-languages) عالی است.

مثال اول: تغییر کاراکتر کامنت (Interactive)

در شل معمولی # کامنت است، اما شاید در فایل فرمت خاص شما % کامنت باشد.

Python

مثال دوم: کنترل POSIX Mode

حالت posix=True (پیش‌فرض در split) رفتار استاندارد یونیکس را دارد. اما اگر posix=False باشد، رفتار قدیمی‌تر و سازگارتر با ویندوز یا سیستم‌های قدیمی را شبیه‌سازی می‌کند. تفاوت اصلی در نحوه برخورد با کوتیشن‌ها و کاراکترهای Wildcard است.

Python

۴. نکات فنی و Best Practices

  1. همیشه برای subprocess: هنگام استفاده از subprocess.run(..., shell=True) حتماً از shlex.quote استفاده کنید، هرچند پیشنهاد می‌شود همیشه shell=False استفاده کرده و لیست آرگومان‌ها را به subprocess بدهید.
  2. Unicode: ماژول shlex در پایتون ۳ کاملاً با یونیکد سازگار است، اما در حالت posix=False ممکن است روی بایت‌های خاصی رفتار متفاوتی نشان دهد.
  3. مدیریت خطا: متد split ممکن است ValueError برگرداند اگر کوتیشن‌ها بسته نشده باشند (مثلاً "open quote).
Python