دستکاری رشته‌ها

فصل ‎10‎- دستکاری متغیرها

‎10.1‎- دستکاری رشته‌ها

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

طول رشته

‎${#string}‎

‎expr length $string‎

اینها معادل‌های ‎strlen()‎ در C هستند.

‎expr "$string" : '.*'‎

stringZ=abcABC123ABCabc

echo ${#stringZ}                 #
echo `expr length $stringZ`      #
echo `expr "$stringZ" : '.*'`    #

مثال ‎10-1‎. درج یک سطر خالی بین پاراگراف‌ها در یک فایل متن

#!/bin/bash
#
#

#
#

MINLEN=60        # 
#  فرض کنید سطرهای کوتاهتر از ‎$MINLEN‎ کاراکتر که با یک نقطه ختم
#+می‌شوند، یک پاراگراف را خاتمه می‌دهند. تمرین‌های زیر را ببینید.

while read line  # 
do
  echo "$line"   # 

  len=${#line}
  if [[ "$len" -lt "$MINLEN" && "$line" =~ [*{\.}]$ ]]
#
#   یک به‌روزرسانی برای ‎Bash‎ نگارش قبلی این اسکریپت را نقض کرد.‏ آخ!‏
# با تشکر از ‎Halim Srama‎ برای اشاره به این مورد و پیشنهاد اصلاحیه.
    then echo            #
  fi                     #+  
done
exit

#                       
#                        ---------
#    اسکریپت معمولاً یک سطر خالی در انتهای فایل هدف    ‎1)‎
#+                اضافه می‌کند. این مورد را اصلاح کنید. 
#    سطر ‎17‎ فقط نقطه را به عنوان خاتمه‌دهنده در نظر   ‎2)‎
#   می‌گیرد. این مورد را ویرایش کنید تا سایر کاراکترهای
#+          انتهای جمله از قبیل ‎?‎‏، ‎!‎، و ‎"‎ را نیز شامل شود.

طول رشته فرعی مطابقت یافته از ابتدای رشته

‎expr match "$string" '$substring'‎

‎$substring‎ یک عبارت منظم است.

‎expr "$string" : '$substring'‎

‎$substring‎ یک عبارت منظم است.

stringZ=abcABC123ABCabc
#
#

echo `expr match "$stringZ" 'abc[A-Z]*.2'`   #
echo `expr "$stringZ" : 'abc[A-Z]*.2'`       #

Index

‎expr index $string $substring‎

شماره اولین موقعیتی در ‎$string‎ که کاراکتری از ‎$substring‎ نخست در آنجا منطبق می‌شود.

stringZ=abcABC123ABCabc
#
echo `expr index "$stringZ" C12`             #
                                             #
echo `expr index "$stringZ" 1c`              #
# ‎'c'‎ (در موقعیت شماره ‎3‎ ) قبل از ‎'1'‎ منطبق می‌شود.

این معادل تقریبی ‎strchr()‎ در C است.

استخراج رشته فرعی

‎${string:position}‎

رشته فرعی از موقعیت ‎$position‎ تا انتهای رشته ‎$string‎ استخراج می‌کند.

اگر به جای ‎string‎ کاراکتر * یا @ قرار گیرد، آنوقت این ترکیب، پارامترهای مکانی را با شروع از پارامتر شماره ‎$position‎ استخراج می‌کند.‎[1]‎

‎${string:position:length}‎

یک رشته فرعی به طول ‎$length‎ کاراکتر از محل ‎$position‎ از رشته ‎$string‎ استخراج می‌کند.

stringZ=abcABC123ABCabc
#
#

echo ${stringZ:0}                    #
echo ${stringZ:1}                    #
echo ${stringZ:7}                    #

echo ${stringZ:7:3}                  #
                                     #


#      
    
echo ${stringZ:-4}                   #
# رشته کامل، همچون در ‎${parameter:-default}‎ تعبیر می‌کند.
                                     #

echo ${stringZ:(-4)}                 #
echo ${stringZ: -4}                  #
                                     #
# پرانتزها یا فاصله اضافه شده پارامتر موقعیت را پوشش می‌دهند.

#           با تشکر از ‎Dan Jacobson‎ برای روشن کردن این مطلب.

شناسه‌های position و length می‌توانند «پارامتری» بشوند، یعنی به جای یک ثابت عددی به صورت یک متغیر بیان گردند.

مثال ‎10-2‎. تولید یک رشته «تصادفی» ۸ کاراکتری

#!/bin/bash
#
#

if [ -n "$1" ]   #    
then             #+
  str0="$1"
else             # وگرنه از ‎PID‎ اسکریپت به عنوان رشته شروع استفاده شود.
  str0="$$"
fi

POS=2            # شروع از موقعیت ‎2‎ در رشته.
LEN=8            #       

str1=$( echo "$str0" | md5sum | md5sum )
                 #      درهم آمیختن دوگانه  ‎^^^^^^   ^^^^^^‎
                 #+   

randstring="${str1:$POS:$LEN}"
                 #  اینها می‌توانند پارامتر باشند  ^^^^ ^^^^

echo "$randstring"

exit $?

#
#

#
#+

اگر به جای ‎string‎ کاراکتر * یا @ قرار گیرد، آنوقت این ترکیب، حداکثر به تعداد ‎$length‎ پارامتر مکانی را با شروع از پارامتر شماره ‎$position‎ استخراج می‌کند.

echo ${*:2}          #
echo ${@:2}          #

echo ${*:2:3}        #

expr substr $string $position $length

تعداد ‎$length‎ کاراکتر از رشته ‎$string‎ با شروع از محل ‎$position‎ استخراج می‌کند.

stringZ=abcABC123ABCabc
#
#

echo `expr substr $stringZ 1 2`              #
echo `expr substr $stringZ 4 3`              #

‎expr match "$string" '\($substring\)'‎

‎$substring‎ را از ابتدای رشته ‎$string‎ استخراج می‌کند، که در اینجا ‎$substring‎ یک عبارت منظم است.

‎expr "$string" : '\($substring\)'‎

‎$substring‎ در ابتدای رشته ‎$string‎ را استخراج می‌کند، که ‎$substring‎ یک عبارت منظم است.

stringZ=abcABC123ABCabc
#	    
echo `expr match "$stringZ" '\(.[b-c]*[A-Z]..[0-9]\)'`   #
echo `expr "$stringZ" : '\(.[b-c]*[A-Z]..[0-9]\)'`       #
echo `expr "$stringZ" : '\(.......\)'`                   #
#

‎expr match "$string" '.*\($substring\)'‎

‎$substring‎ را از انتهای رشته ‎$string‎ استخراج می‌کند، که ‎$substring‎ در آن یک عبارت منظم است.

‎expr "$string" : '.*\($substring\)'‎

‎$substring‎ را از انتهای رشته ‎$string‎ استخراج می‌کند، که در آن ‎$substring‎ یک عبارت منظم است.

stringZ=abcABC123ABCabc
#

echo `expr match "$stringZ" '.*\([A-C][A-C][A-C][a-c]*\)'`    #
echo `expr "$stringZ" : '.*\(......\)'`                       #

پاک کردن رشته فرعی

‎${string#substring}‎

کوتاهترین انطباق ‎$substring‎ را از جلوی ‎$string‎ حذف می‌کند.

‎${string##substring}‎

بلندترین مورد انطباق ‎$substring‎ را از جلوی رشته ‎$string‎ حذف می‌کند.

stringZ=abcABC123ABCabc
#
#

echo ${stringZ#a*C}      #
#         پاک کردن کوتاهترین مورد انطباق بین ‎'a'‎ و ‎'C'‎.

echo ${stringZ##a*C}     #
#          پاک کردن بلندترین مورد انطباق بین ‎'a'‎ و ‎'C'‎.

#

X='a*C'

echo ${stringZ#$X}      #
echo ${stringZ##$X}     #
                        #

‎${string%substring}‎

کوتاهترین مورد انطباق ‎$substring‎ را از انتهای ‎$string‎ حذف می‌کند.

برای مثال:

#  تغییر تمام پسوندهای ‎«TXT»‎ فایلهای داخل ‎$PWD‎ با پسوند «txt»
#          به عنوان مثال، ‎"file1.TXT"‎ می‌شود ‎"file1.txt"‎ . . .

SUFF=TXT
suff=txt

for i in $(ls *.$SUFF)
do
  mv -f $i ${i%.$SUFF}.$suff
       # 
       #+       الگوی منطبق شده از سمت راست متغیر ‎$i‎ . . .
done ###

# با تشکر از ‎Rory Winston‎

‎${string%%substring}‎

طولانی‌ترین مورد تطبیق ‎$substring‎ از انتهای رشته ‎$string‎ حذف می‌شود.

stringZ=abcABC123ABCabc
#
#

echo ${stringZ%b*c}      #
# کوتاهترین مورد انطباق بین ‎'b'‎ و ‎'c'‎ با انتهای رشته ‎$stringZ‎ را پاک می‌کند.

echo ${stringZ%%b*c}     #
#   بلندترین مورد تطبیق بین ‎'b'‎ و ‎'c'‎ با انتهای رشته ‎$stringZ‎ را پاک می‌کند.

این عامل برای تولید نام فایلها سودمند است.

مثال ‎10-3‎. تبدیل قالب فایلهای گرافیکی، با تغییر نام فایل

#!/bin/bash
#
#  تمام فایهای تصویری ‎MacPaint‎ در یک دایرکتوری را به قالب ‎"pbm"‎ تبدیل می‌کند.

#   برنامه ‎"macptopbm"‎ از بسته ‎"netpbm"‎ را به کار می‌برد، که توسط
#+     ‎Brian Henderson (bryanh@giraffe-data.com)‎ پشتیبانی می‌شود.
#              ‎Netpbm‎ یک بخش استاندارد اکثر توزیع‌های لینوکس است.

OPERATION=macptopbm
SUFFIX=pbm          # 

if [ -n "$1" ]
then
  directory=$1      #
else
  directory=$PWD    #      
fi  
  
#   فرض می‌کند تمام فایلها در دایرکتوری هدف فایلهای تصویری
#+      ‎MacPaint‎ با یک پسوند نام فایل به صورت ‎.mac‎ هستند.

for file in $directory/*    #
do
  filename=${file%.*c}      #      زدودن پسوند ‎.mac‎ از نام فایل
                            #+  (‎'.*c'‎ ‎با هر چیزی بین ‎'.'‎ و ‎'c'‎
			    #+   و شامل خود آنها، منطبق می‌شود).
  $OPERATION $file > "$filename.$SUFFIX"
                            #  
  rm -f $file               #      
  echo "$filename.$SUFFIX"  #
done

exit 0

#                                 
#                                -----------
# 
#   آن را ویرایش کنید که «فقط» بر فایلهای دارای پسوند ‎".mac"‎ عمل کند.



#                  #

#!/bin/bash
#                            
#  فرض می‌کند ‎imagemagick‎ نصب شده است (استانداردِ اکثر توزیع‌های لینوکس)‏.

INFMT=png                  #       می‌تواند tif‏، jpg‏، gif‏، و غیره باشد.
OUTFMT=pdf                 #  می‌تواند tif‏، jpg‏، gif‏، pdf‏، و غیره باشد.

for pic in *"$INFMT"
do
  p2=$(ls "$pic" | sed -e s/\.$INFMT//)
  #
    convert "$pic" $p2.$OUTFMT
    done

exit $?

مثال ‎10-4‎. تبدیل فایلهای صوتی جریانی به ogg

#!/bin/bash
# ‎ra2ogg.sh‎: تبدیل فایلهای صوتی جریانی ‎(*.ra)‎ به ogg.

# از برنامه پخش  صوتی وتصویری ‎"mplayer"‎ استفاده می‌کند:
#
#   فایلهای کتابخانه ‎"ogg"‎ و ‎"oggenc"‎ را به کار می‌برد:
#
#
#  این اسکریپت ممکن است به codecهای نصب شده مناسب از قبیل ‎sipr.so‎ 
#       و همچنین احتمالاً به بسته ‎compat-libstdc++‎ نیاز داشته باشد.


OFILEPREF=${1%%ra}      #     زدودن پسوند ‎"ra"‎
OFILESUFF=wav           #  پسوند برای فایل ‎wav‎
OUTFILE="$OFILEPREF""$OFILESUFF"
E_NOARGS=85

if [ -z "$1" ]          #
then
  echo "Usage: `basename $0` [filename]"
  exit $E_NOARGS
fi


##########################################################################
mplayer "$1" -ao pcm:file=$OUTFILE
oggenc "$OUTFILE"  # پسوند صحیح فایل به طور خودکار توسط ‎oggenc‎ اضافه شده.
##########################################################################

rm "$OUTFILE"      #                               حذف فایل واسطه ‎*.wav‎
                   #

exit $?

#                             نکته:
#                          
#     در یک وب‌سایت، معمولاً به آسانی با کلیک روی یک فایل صوتی 
#+  جریانی ‎*.ram‎  فقط آدرس ‎URL‎ فایل صوتی واقعی ‎*.ra‎ دریافت
#   می‌شود. سپس شما می‌توانید با ‎"wget"‎ یا موردی مشابه آن، خود
#+                             فایل ‎*.ra‎ را دانلود نمایید.


#                           تمرین‌ها
#                         
#     مطابق معمول، اسکریپت فقط نام فایلهای ‎*.ra را تبدیل می‌کند. با اجازهِ
#  استفاده از ‎*.ram‎ و سایر نام فایلها، قابلیت انعطاف آن را افزایش بدهید.
#
# 
#+    
#     یک ‎URL‎ مشخص شده، دانلود دسته‌ای فایلهای صوتی جریانی
#+             (با استفاده از wget) و تبدیل درجای آنها.

یک شبیه‌سازی ساده از getopt با استفاده از ساختارهای استخراج رشته‌ فرعی.

مثال ‎10-5‎. شبیه‌سازی getopt

#!/bin/bash
# 
#  مولف: ‎Chris Morgan‎
# با مجوز در این راهنما استفاده شده است .


getopt_simple()
{
    echo "getopt_simple()"
    echo "Parameters are '$*'"
    until [ -z "$1" ]
    do
      echo "Processing parameter of: '$1'"
      if [ ${1:0:1} = '/' ]
      then
          tmp=${1:1}               # از بین بردن ‎'/'‎ مقدم
          parameter=${tmp%%=*}     #
          value=${tmp##*=}         #
          echo "Parameter: '$parameter', value: '$value'"
          eval $parameter=$value
      fi
      shift
    done
}

#  عبور دادن تمام گزینه‌ها به ‎getopt_simple()‎
getopt_simple $*

echo "test is '$test'"
echo "test2 is '$test2'"

exit 0  # اسکریپت ‎UseGetOpt.sh‎ را نیز ببینید، نگارش اصلاح شدهِ این اسکریپت است.

---

sh getopt_example.sh /test=value1 /test2=value2

Parameters are '/test=value1 /test2=value2'
Processing parameter of: '/test=value1'
Parameter: 'test', value: 'value1'
Processing parameter of: '/test2=value2'
Parameter: 'test2', value: 'value2'
test is 'value1'
test2 is 'value2'

تعویض رشته فرعی

‎${string/substring/replacement}‎

اولین مورد از مطابقت رشته فرعی ‎$substring‎ را با ‎$replacement‎ تعویض می‌کند. ‎[2]‎

‎${string//substring/replacement}‎

تعویض زیر-رشته ‎$substring‎ با ‎$replacement‎.

stringZ=abcABC123ABCabc

echo ${stringZ/abc/xyz}     #
                            #   اولین مورد انطباق ‎'abc'‎ را با ‎'xyz'‎ تعویض می‌کند.

echo ${stringZ//abc/xyz}    #
                            # تمام موارد منطبق با ‎'abc'‎ را با ‎'xyz'‎ تعویض می‌کند.

echo  ---------------
echo "$stringZ"             #
echo  ---------------
                            #

#
match=abc
repl=000
echo ${stringZ/$match/$repl}  #
#
echo ${stringZ//$match/$repl} #
#

echo

#در صورتیکه رشته ‎$replacement‎ ارایه نشود، چه اتفاقی رخ می‌دهد؟
echo ${stringZ/abc}           #
echo ${stringZ//abc}          #
#                                     

‎${string/#substring/replacement}‎

اگر ‎$substring‎ با بخشی از ابتدای ‎‎$string‎‎ مطابقت کند، ‎$replacement‎ جایگزین ‎‎$substring‎‎ می‌گردد.

‎${string/%substring/replacement}‎‎

اگر ‎‎$substring‎‎ با قسمت انتهایی ‎‎$string‎‎ منطبق باشد، ‎$replacement‎ جایگزین ‎$substring‎ می‌شود.

stringZ=abcABC123ABCabc

echo ${stringZ/#abc/XYZ}     #
                             # مورد انطباق پیشانی ‎'abc'‎ را با ‎'XYZ'‎ تعویض می‌کند.

echo ${stringZ/%abc/XYZ}     #
                             #      انطباق پایانی ‎'abc'‎ را با ‎'XYZ'‎ تعویض می‌کند.

‎10.1.1‎- دستکاری رشته‌ها بااستفاده از awk

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

مثال ‎10-6‎. روشهای جایگزین استخراج و جایگزینی رشته‌های فرعی

#!/bin/bash
#

String=23skidoo1
#
#
#           
# Bash کاراکتر اول رشته را به عنوان ‎0‎ شماره‌گذاری می‌کند.
# Awk اولین کاراکتر رشته را به عنوان ‎1‎ شماره‌گذاری می‌کند.

echo ${String:2:4} # مکان سوم ‎(0-1-2)‎‏ ‎, طول 4‎ کاراکتر
                                         #

# معادل ‎${string:pos:length}‎ در awk برابر با ‎substr(string,pos,length)‎ است.
echo | awk '
{ print substr("'"${String}"'",3,4)      #
}
'
#   لوله‌کشی یک "echo" خالی به awk ورودی زائدی به آن می‌دهد، و
#+    

echo "----"

#

echo | awk '
{ print index("'"${String}"'", "skid")      #
}                                           # (‎skid‎ در موقعیت ‎3‎ شروع می‌شود)
'                                           # معادل ‎awk‎ از ‎"expr index"‎ ...

exit 0

‎10.1.2‎- منابع بیشتر

برای آشتایی بیشتر با دستکاری رشته در اسکریپت‌ها، به بخش ‎10.2‎ و بخش مربوط به فرمان expr مراجعه کنید.

اسکریپت‌های نمونه:

  1. مثال ‎ 16-9‎

  2. مثال ‎ 10-9‎

  3. مثال ‎ 10-10‎

  4. مثال ‎ 10-11‎

  5. مثال ‎ 10-13‎

  6. مثال ‎ A-36‎

  7. مثال ‎ A-41‎

یادداشت‌ها

[1]

این در مورد شناسه‌های خط فرمان یا پارامترهای عبور داده شده به یک تابع صدق می‌کند.

[2]

توجه نمایید که ‎$substring‎ و ‎$replacement‎ بر اساس مضمون می‌توانند به رشته‌های لفظی یا متغیرها اشاره کنند.