تعویض رشته‌ها - آموزش اسکریپت نویسی
X
تبلیغات
رایتل

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

آموزش اسکریپت نویسی پوسته گنو-لینوکس

#!/bin/bash

تعویض رشته‌ها

تعویض رشته‌ها

محتویات       

  1. متغیرها
  2. جریانها

متغیرها

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

var='some string'; search=some; rep=another

# Bash در‎
var=${var//"$search"/$rep}


# POSIX تابع‎

# usage: string_rep SEARCH REPL STRING
# تعویض می‌کند REPL را با STRING در SEARCH تمام نمونه‌های‎
string_rep() {
  # مقدار دهی آغازین‎
  in=$3
  unset out

  # نباید تهی باشد SEARCH ‎
  [ "$1" ] || return

  while true; do
    # نباشد "$in" دیگر شامل SEARCH انقطاع حلقه در صورتیکه ‎
    case "$in" in
      *"$1"*) : ;;
      *) break;;
    esac

    #  "$out" در REP بعلاوه SEARCH تا رسیدن به اولین نمونه "$in" پیوست کردن هر چیز از ‎
    out=$out${in%%"$1"*}$2
    # "$in" و خود این نمونه از SEARCH حذف هرچیز تا رسیدن به اولین نمونه ‎
    in=${in#*"$1"}
  done

  # و چاپ out باقی مانده است به "$in" در SEARCH ضمیمه هر آنچه بعد از آخرین نمونه ‎
  printf '%s%s\n' "$out" "$in"
}

var=$(string_rep "$search" "$rep" "$var")

توجه: POSIX روشی برای موضعی ساختن متغیرها ندارد. هر چند، اکثر پوسته‌ها (حتی dash و busybox) دارند. اگر پوسته شما از آن پشتیبانی می‌کند از موضعی ساختن متغیرها آسوده خاطر باشید. حتی اگر پشتیبانی نمی‌کند، اگر تابع را با ‎var=$(string_rep ...)‎ فراخوانی کنید، تابع یک پوسته فرعی اجرا خواهد نمود و هر تخصیصی که انجام دهد سماجت نخواهد کرد.

در مثال bash، نقل‌قولهای اطراف ‎"$search"‎ از رفتار شدن با محتوای متغیر به عنوان یک الگوی پوسته (glob نیز نامیده شده)، پیش‌گیری می‌کنند. البته، در صورتیکه انطباق الگو مورد نظر است، نقل‌قولها را ضمیمه نکنید. به هرحال، اگر ‎"$rep"‎ نقل‌قولی شده بود، با نقل‌قولها به عنوان کاراکترهای لفظی رفتار می‌گردید.

بسط پارامترهایی مانند این مورد با تفصیل بیشتر در پرسش و پاسخ شماره ۱۰۰ بحث گردیده‌اند.

جریانها

اگر یک فایل یا جریان باشد، مسائل یک مقدار کمی ماهرانه می‌شوند. ابزارهای استاندارد معتبر برای این مورد sed یا AWK (برای جریانها)، و ed (برای فایلها) می‌باشند.

البته، خودتان می‌توانید در bash از طریق ترکیب روش قبلی با پرسش و پاسخ شماره ۱ آن را انجام بدهید:

search=foo; rep=bar

while IFS= read -r line; do
  printf '%s\n' "${line//"$search"/$rep}"
done < <(some_command)

some_command | while IFS= read -r line; do
  printf '%s\n' "${line//"$search"/$rep}"
done

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

البته، یک گزینه دیگر sed خواهد بود:

# تعویض می‌کند "replace" را با "some_command" در خروجی "search" تمام نمونه‌های ‎
some_command | sed 's/search/replace/g'

sed عبارتهای منظم را به کار می‌برد. بر خلاف bash، به منظور رفتار کردن بامقادیر به عنوان رشته‌های لفظی "search" و "replace" شدیداً باید پوشش یافته می‌شدند. این کار بسیار غیر عملی است، و کوشش برای انجام آن کُد شما را به شدت مستعد باگ‌ها خواهد نمود. تعبیه متغیرهای پوسته در sed هرگز ایده مناسبی نیست.

به هر حال، ممکن است توجه نمایید که حلقه bash فوق برای مجموعه‌های بزرگ اطلاعات خیلی کُند است. بنابراین چطور مورد سریع‌تری پیدا کنیم، که بتواند رشته‌های لفظی را تعویض کند؟ خوب، می‌توانید AWK را به کار ببرید. تابع زیر تمام نمونه‌های STR با REP را تعویض می‌کند، با خواندن از stdin و نوشتن در stdout.

# usage: gsub_literal STR REP
# می‌نویسد stdout را می‌خواند و در stdin .تعویض می‌کند REP را با STR تمام نمونه‌های ‎
gsub_literal() {
  # نمی‌تواند تهی باشد STR ‎
  [[ $1 ]] || return

  # و مانند آن باز داشته شود '\n' از بسط awk ها پوشانده شود  تا ‎'\'‎ لازم است رشته با‎
  awk -v str="${1//\\/\\\\}" -v rep="${2//\\/\\\\}" '
    # به دست آوردن طول رشته جستجو‎
    BEGIN {
      len = length(str);
    }

    {
      # تهی کردن رشته خروجی‎
      out = "";

      # ادامه حلقه مادامیکه رشته جستجو در سطر وجود دارد‎
      while (i = index($0, str)) {
        # پیوست کردن هر چیز تا رشته جستجو، و رشته جایگزین‎ string
        out = out substr($0, 1, i-1) rep;

        # حذف کردن همه چیز تا اولین نمونه جستجو و خود نمونه از سطر‎
        $0 = substr($0, i + len);
      }

      # پیوست کردن هر آنچه باقی مانده‎
      out = out $0;

      print out;
    }
  '
}

some_command | gsub_literal "$search" "$rep"


# خلاصه شده به عنوان یک سطر‎:
some_command | awk -v s="${search//\\/\\\\}" -v r="${rep//\\/\\\\}" 'BEGIN {l=length(s)} {o="";while (i=index($0, s)) {o=o substr($0,1,i-1) r; $0=substr($0,i+l)} print o $0}'


CategoryShell

تعویض رشته‌ها (آخرین ویرایش ‎2013-04-15 19:58:23‎ توسط geirha)