آموزش‌های خط فرمانی

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

آموزش‌های خط فرمانی

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

تبدیل کاراکتر به دسیمال یا هگزا


چطور می‌توانم یک کاراکتر اسکی را به مقدار دسیمال(یا هگزادسیمال) آن و برعکس تبدیل نمایم؟

اگر شما یک مقدار معین هگزادسیمال یا اُکتال دارید(در زمان نوشتن اسکریپت)، دقیقاً می‌توانید printf را به کار ببرید:

   # POSIX
   printf '\x27\047\n'

این کُد دو کاراکتر لفظی ' (27 مقدار هگزادسیمال کاراکتر اسکی و 47 مقدار اُکتال آن است) و یک سطر جدید را چاپ می‌کند.

   ExpandedString=$'\x27\047\u0027\U00000027\n'
   echo -n "$ExpandedString"

یک رویکرد دیگر، رشته‌های ‎$'...'‎ قبل از ارزیابی ، [در متغیری]پوشش داده می‌شوند و می‌توانند به طور مستقیم در کُد تعبیه شوند.

اگر احتیاج دارید کاراکترها(یا مقادیر عددی کاراکتر اسکی) که از قبل شناخته شده نیستند(به عنوان مثال در متغیرها) را تبدیل کنید، می‌توانید ازکُد کمی پیچیده‌تر استفاده کنید:

# POSIX
# chr() - مقدار دسیمال را به کاراکتر اسکی نماینده‌اش تبدیل می‌کند
# ord() - کاراکتر اسکی را به مقدار دسیمال آن تبدیل می‌کند

chr() {
  [ ${1} -lt 256 ] || return 1
  printf \\$(printf '%03o' $1)
}

# یک نگارش دیگر با تبدیل به اُکتال با استفاده از محاسبه ‎
# سریعتر به علت آنکه از پوسته فرعی اجتناب می‌کند‎
chr () {
  [ ${1} -lt 256 ] || return 1
  printf \\$(($1/64*100+$1%64/8*10+$1%8))
}

# نگارش دیگر با استفاده از متغیر موقت برای اجتناب از پوسته فرعی ‎
# نیاز دارد bash 3.1 این روش به ‎
chr() {
  local tmp
  [ ${1} -lt 256 ] || return 1
  printf -v tmp '%03o' "$1"
  printf \\"$tmp"
}

ord() {
  LC_CTYPE=C printf '%d' "'$1"
}

# hex() - کاراکتر اسکی را به مقدار هگزادسیمال تبدیل می‌کند‎
# unhex() - مقدار هگزادسیمال را به کاراکتر اسکی تبدیل می‌کند‎

hex() {
   LC_CTYPE=C printf '%x' "'$1"
}

unhex() {
   printf \\x"$1"
}

# :مثالها‎

chr $(ord A)    # ==> A
ord $(chr 65)   # ==> 65

تابع ord بالا کاملاًماهرانه است.

  • ماهرانه؟ نسبتاً، این تابع از یک ویژگی استفاده می‌کند که من مستند شده آن را درجایی نمی توانم پیدا کنم --گذاشتن یک نقل‌قول منفرد در جلوی یک عدد صحیح. تأثیر شسته رُفته، اما در این دنیای فانی چطور آن را کشف کردید؟ شیرجه رفتن در کُد منبع؟ -- GreyCat

    • این خصوصیات یگانه یونیکس را تأیید می‌کند: «اگر کاراکتر مقدم نقل‌قول منفرد یا دوگانه باشد، کمیت پس از آن متضمن یک مقدار عددی در مجموعه کُد(codeset) کاراکتر بعد از نقل‌قول می‌باشد.» (برای آگاهی بیشتر ‎printf()‎ را ملاحظه کنید) ‎-- mjf

مثالهای کامل‌تر (با پشتیبانی از ‎UTF-8‎ )

  • مثال پایین اخیراً کاملاً پذیرفته شد و لازم است پاکیزه و تأیید اعتبار بشود.

به( encoding) کُدگذاری ‎Ext Ascii‎ و ‎UTF-8‎ توجه نمایید

  • برای مقادیر ‎ 0x00 - 0x7f‎ کاملاً یکسان
  • برای مقادیر ‎ 0x80 - 0xff‎ ناسازگاری بین ‎UTF-8‎ و ExtAscii

  • برای مقادیر ‎ 0x100 - 0xffff‎ فقط در ‎ UTF-8 UTF-16 UTF-32‎ معتبر است
  • برای مقادیر ‎ 0x100 - 0x7FFFFFFF‎ فقط در ‎UTF-8 UTF-32‎ معتبر است

    مقدار

    EAscii

    UTF-8

    UTF-16

    UTF-32

    0x20

    "\x20"

    "\x20"

    \u0020

    \U00000020

    0x20

    "\x7f"

    "\x7f"

    \u007f

    \U0000007f

    0x80

    "\x80"

    "\xc2\x80"

    \u0080

    \U00000080

    0xff

    "\xff"

    "\xc3\xbf"

    \u00ff

    \U000000ff

    0x100

    N/A

    "\xc4\x80"

    \u0100

    \U00000100

    0x1000

    N/A

    "\xc8\x80"

    \u1000

    \U00001000

    0xffff

    N/A

    "\xef\xbf\xbf"

    \uffff

    \U0000ffff

    0x10000

    N/A

    "\xf0\x90\x80\x80"

    \ud800\udc00

    \U00010000

    0xfffff

    N/A

    "\xf3\xbf\xbf\xbf"

    \udbbf\udfff

    \U000fffff

    0x10000000

    N/A

    "\xfc\x90\x80\x80\x80\x80"

    N/A

    \U10000000

    0x7fffffff

    N/A

    "\xfd\xbf\xbf\xbf\xbf\xbf"

    N/A

    \U7fffffff

    0x80000000

    N/A

    N/A

    N/A

    N/A

    0xffffffff

    N/A

    N/A

    N/A

    N/A

  ###########################################################################
  ##         برای تبدیل کاراکتر به عدد ord خانواده‎
  ###########################################################################
  # ord             ‎< نام متغیر بازگشتی >‎ < کاراکتر > ‎ [رشته قال‌بندی اختیاری]‎
  # ord_hex         ‎‎< نام متغیر بازگشتی >‎ < کاراکتر >
  # ord_oct         ‎‎< نام متغیر بازگشتی >‎ < کاراکتر >
  # ord_utf8        ‎‎< نام متغیر بازگشتی >‎ < کاراکتر > ‎ [رشته قال‌بندی اختیاری]
  # ord_eascii      ‎‎< نام متغیر بازگشتی >‎ < کاراکتر > ‎ [رشته قال‌بندی اختیاری]‎
  # ord_echo                              < کاراکتر > ‎ [رشته قال‌بندی اختیاری]
  # ord_hex_echo                          < کاراکتر >
  # ord_oct_echo                          < کاراکتر >
  # ord_utf8_echo                         < کاراکتر > ‎ [رشته قال‌بندی اختیاری]
  # ord_eascii_echo                       < کاراکتر > ‎ [رشته قال‌بندی اختیاری]‎
  #
 ‏‎ #  : توضیحات‎
  # محلی را تبدیل می‌کند و مقدار encoding کاراکتر به کار رفته با ‎
  # آن را در متغیر تعیین شده ذخیره می‌کند‎
  #
  #       ord
  #       ord_hex         خروجی به هگزا
  #       ord_oct         خروجی اُکتال
  #       ord_utf8        UTF8 اجباری decoding
  #       ord_eascii      اجباری دسیمال decoding
  #       ord_echo        چاپ در خروجی استاندارد
  function ord {
          printf -v "${1?Missing Dest Variable}" "${3:-%d}" "'${2?Missing Char}"
  }
  function ord_oct {
          ord "${@:1:2}" "0%o"
  }
  function ord_hex {
          ord "${@:1:2}" "0x%x"
  }
  function ord_utf8 {
          LC_CTYPE=C.UTF-8 ord "${@}"
  }
  function ord_eascii {
          LC_CTYPE=C ord "${@}"
  }
  function ord_echo {
          printf "${2:-%d}" "'${1?Missing Char}"
  }
  function ord_oct_echo {
          ord_echo "${1}" "0%o"
  }
  function ord_hex_echo {
          ord_echo "${1}" "0x%x"
  }
  function ord_utf8_echo {
          LC_CTYPE=C.UTF-8 ord_echo "${@}"
  }
  function ord_eascii_echo {
          LC_CTYPE=C ord_echo "${@}"
  }

  ###########################################################################
  ##          برای تبدیل عدد به کاراکتر chr خانواده‎
  ###########################################################################
  # chr_utf8   ‎< نام متغیر بازگشتی > ‎< عدد صحیح برای تبدیل >‎
  # chr_eascii ‎< نام متغیر بازگشتی > ‎< عدد صحیح برای تبدیل >
  # chr        ‎< نام متغیر بازگشتی > ‎< عدد صحیح برای تبدیل >
  # chr_oct    ‎< نام متغیر بازگشتی > ‎< عدد اُکتال برای تبدیل >
  # chr_hex    ‎< نام متغیر بازگشتی > ‎< عدد هگزا برای تبدیل >
  # chr_utf8_echo                    ‎< عدد صحیح برای تبدیل >
  # chr_eascii_echo                  ‎< عدد صحیح برای تبدیل >
  # chr_echo                         ‎< عدد صحیح برای تبدیل >
  # chr_oct_echo                     ‎< عدد اُکتال برای تبدیل >
  # chr_hex_echo                     ‎< عدد هگزا برای تبدیل >
  #
  #     : توضیحات
  # مقدار دسیمال را به کاراکتری که آن را نمایندگی‎
  # می‌کند تبدیل و متغیر تعیین شده ذخیره می‌کند‎
  #
  #       chr                     سعی می‌کند قالب خروجی را حدس بزند
  #       chr_utf8                UTF8 اجباری encoding
  #       chr_eascii              eascii اجباری encoding
  #       chr_echo                چاپ در خروجی استاندارد
  #
  function chr_utf8_m {
    local val
    #
    #  پشتیبانی می‌کند ‎\u \U ‎از ‎4.2‎ فقط از نگارش ‎bash‎‎
    #

    #  این یک مثال از چگونگی کُد گذاری به طور دستی است‎‎
    # استفاده می‌کند کار خواهد کرد -v که از Bash 3.1 از نگارش ‎
    #
    if [[ ${2:?Missing Ordinal Value} -le 0x7f ]]; then
      printf -v val "\\%03o" "${2}"
    elif [[ ${2} -le 0x7ff        ]]; then
      printf -v val "\\%03o\\%03o" \
        $((  (${2}>> 6)      |0xc0 )) \
        $(( ( ${2}     &0x3f)|0x80 ))
    elif [[ ${2} -le 0xffff       ]]; then
      printf -v val "\\%03o\\%03o\\%03o" \
        $(( ( ${2}>>12)      |0xe0 )) \
        $(( ((${2}>> 6)&0x3f)|0x80 )) \
        $(( ( ${2}     &0x3f)|0x80 ))
    elif [[ ${2} -le 0x1fffff     ]]; then
      printf -v val "\\%03o\\%03o\\%03o\\%03o"  \
        $(( ( ${2}>>18)      |0xf0 )) \
        $(( ((${2}>>12)&0x3f)|0x80 )) \
        $(( ((${2}>> 6)&0x3f)|0x80 )) \
        $(( ( ${2}     &0x3f)|0x80 ))
    elif [[ ${2} -le 0x3ffffff    ]]; then
      printf -v val "\\%03o\\%03o\\%03o\\%03o\\%03o"  \
        $(( ( ${2}>>24)      |0xf8 )) \
        $(( ((${2}>>18)&0x3f)|0x80 )) \
        $(( ((${2}>>12)&0x3f)|0x80 )) \
        $(( ((${2}>> 6)&0x3f)|0x80 )) \
        $(( ( ${2}     &0x3f)|0x80 ))
    elif [[ ${2} -le 0x7fffffff ]]; then
      printf -v val "\\%03o\\%03o\\%03o\\%03o\\%03o\\%03o"  \
        $(( ( ${2}>>30)      |0xfc )) \
        $(( ((${2}>>24)&0x3f)|0x80 )) \
        $(( ((${2}>>18)&0x3f)|0x80 )) \
        $(( ((${2}>>12)&0x3f)|0x80 )) \
        $(( ((${2}>> 6)&0x3f)|0x80 )) \
        $(( ( ${2}     &0x3f)|0x80 ))
    else
      printf -v "${1:?Missing Dest Variable}" ""
      return 1
    fi
    printf -v "${1:?Missing Dest Variable}" "${val}"
  }
  function chr_utf8 {
          local val
          [[ ${2?Missing Ordinal Value} -lt 0x80000000 ]] || return 1

          if [[ ${2} -lt 0x100 && ${2} -ge 0x80 ]]; then

                  # bash 4.2 incorrectly encodes
                  # \U000000ff as \xff so encode manually
                  printf -v val "\\%03o\%03o" $(( (${2}>>6)|0xc0 )) $(( (${2}&0x3f)|0x80 ))
          else
                  printf -v val '\\U%08x' "${2}"
          fi
          printf -v ${1?Missing Dest Variable} ${val}
  }
  function chr_eascii {
          local val
          # کوچکتر است ‎0x100‎ کسب اطمینان که کمیت از‎
          # در غیر این صورت به این شکل تمام می‌کنیم‎
          # \xVVNNNNN
          # می‌باشد \xVV = char یک رشته عددی و NNNNN که در آن‎
          #  chr "0x44321" => "D321" به طوری که‎
          [[ ${2?Missing Ordinal Value} -lt 0x100 ]] || return 1
          printf -v val '\\x%02x' "${2}"
          printf -v ${1?Missing Dest Variable} ${val}
  }
  function chr {
          if [ "${LC_CTYPE:-${LC_ALL:-}}" = "C" ]; then
                  chr_eascii "${@}"
          else
                  chr_utf8 "${@}"
          fi
  }
  function chr_dec {
          # صفرهای مقدم از بین می‌روند در غیر آن صورت ‎
          # به عنوان اُکتا تفسیر می‌شوند‎
          chr "${1}" "${2#${2%%[!0]*}}" 
  }
  function chr_oct {
          chr "${1}" "0${2}"
  }
  function chr_hex {
          chr "${1}" "0x${2#0x}"
  }
  function chr_utf8_echo {
          local val
          [[ ${1?Missing Ordinal Value} -lt 0x80000000 ]] || return 1

          if [[ ${1} -lt 0x100 && ${1} -ge 0x80 ]]; then

                  # bash 4.2 incorrectly encodes
                  # \U000000ff as \xff so encode manually
                  printf -v val '\\%03o\\%03o' $(( (${1}>>6)|0xc0 )) $(( (${1}&0x3f)|0x80 ))
          else
                  printf -v val '\\U%08x' "${1}"
          fi
          printf "${val}"
  }
  function chr_eascii_echo {
          local val
          # کوچکتر است ‎0x100‎ کسب اطمینان که کمیت از‎
          # در غیر این صورت به این شکل تمام می‌کنیم‎
          # \xVVNNNNN
          # می‌باشد \xVV = char یک رشته عددی و NNNNN که در آن‎
          #  chr "0x44321" => "D321" به طوری که
          [[ ${1?Missing Ordinal Value} -lt 0x100 ]] || return 1
          printf -v val '\\x%x' "${1}"
          printf "${val}"
  }
  function chr_echo {
          if [ "${LC_CTYPE:-${LC_ALL:-}}" = "C" ]; then
                  chr_eascii_echo "${@}"
          else
                  chr_utf8_echo "${@}"
          fi
  }
  function chr_dec_echo {
          # صفرهای مقدم از بین می‌روند در غیر آن صورت ‎
          # به عنوان اُکتا تفسیر می‌شوند
          chr_echo "${1#${1%%[!0]*}}" 
  }
  function chr_oct_echo {
          chr_echo "0${1}"
  }
  function chr_hex_echo {
          chr_echo "0x${1#0x}"
  }

  #
  # کُد ساده معتبرسازی ‎
  #
  function test_echo_func {
    local Outcome _result
    _result="$( "${1}" "${2}" )"
    [ "${_result}" = "${3}" ] && Outcome="Pass" || Outcome="Fail"
    printf "# %-20s %-6s => "           "${1}" "${2}" "${_result}" "${3}"
    printf "[ "%16q" = "%-16q"%-5s ] "  "${_result}" "${3}" "(${3//[[:cntrl:]]/_})"
    printf "%s\n"                       "${Outcome}"


  }
  function test_value_func {
    local Outcome _result
    "${1}" _result "${2}"
    [ "${_result}" = "${3}" ] && Outcome="Pass" || Outcome="Fail"
    printf "# %-20s %-6s => "           "${1}" "${2}" "${_result}" "${3}"
    printf "[ "%16q" = "%-16q"%-5s ] "  "${_result}" "${3}" "(${3//[[:cntrl:]]/_})"
    printf "%s\n"                       "${Outcome}"
  }
  test_echo_func  chr_echo "$(ord_echo  "A")"  "A"
  test_echo_func  ord_echo "$(chr_echo "65")"  "65"
  test_echo_func  chr_echo "$(ord_echo  "ö")"  "ö"
  test_value_func chr      "$(ord_echo  "A")"  "A"
  test_value_func ord      "$(chr_echo "65")"  "65"
  test_value_func chr      "$(ord_echo  "ö")"  "ö"
  # chr_echo        65     => [                A = A               (A)   ] Pass
  # ord_echo        A      => [               65 = 65              (65)  ] Pass
  # chr_echo        246    => [      $'\303\266' = $'\303\266'      (ö)  ] Pass
  # chr             65     => [                A = A               (A)   ] Pass
  # ord             A      => [               65 = 65              (65)  ] Pass
  # chr             246    => [      $'\303\266' = $'\303\266'      (ö)  ] Pass
  #


  test_echo_func  chr_echo     "65"     A
  test_echo_func  chr_echo     "065"    5
  test_echo_func  chr_dec_echo "065"    A
  test_echo_func  chr_oct_echo "65"     5
  test_echo_func  chr_hex_echo "65"     e
  test_value_func chr          "65"     A
  test_value_func chr          "065"    5
  test_value_func chr_dec      "065"    A
  test_value_func chr_oct      "65"     5
  test_value_func chr_hex      "65"     e
  # chr_echo      65     => [        A = A                  (A)   ] Pass
  # chr_echo      065    => [        5 = 5                  (5)   ] Pass
  # chr_dec_echo  065    => [        A = A                  (A)   ] Pass
  # chr_oct_echo  65     => [        5 = 5                  (5)   ] Pass
  # chr_hex_echo  65     => [        e = e                  (e)   ] Pass
  # chr           65     => [        A = A                  (A)   ] Pass
  # chr           065    => [        5 = 5                  (5)   ] Pass
  # chr_dec       065    => [        A = A                  (A)   ] Pass
  # chr_oct       65     => [        5 = 5                  (5)   ] Pass
  # chr_hex       65     => [        e = e                  (e)   ] Pass

  #test_value_func chr       0xff   $'\xff'
  test_value_func chr_eascii 0xff   $'\xff'
  test_value_func chr_utf8   0xff   $'\uff'   
  # به طور صحیح آن را رمزگشایی نمی‌کند bash مورد بالا ناموفق است چون‎
  test_value_func chr_utf8   0xff   $'\303\277'
  test_value_func chr_utf8   0x100  $'\u100'
  test_value_func chr_utf8   0x1000 $'\u1000'
  test_value_func chr_utf8   0xffff $'\uffff'
  # chr_eascii       0xff   => [          $'\377' = $'\377'         (�)   ] Pass
  # chr_utf8         0xff   => [      $'\303\277' = $'\377'         (�)   ] Fail
  # chr_utf8         0xff   => [      $'\303\277' = $'\303\277'     (ÿ)   ] Pass
  # chr_utf8         0x100  => [      $'\304\200' = $'\304\200'     (Ā)   ] Pass
  # chr_utf8         0x1000 => [  $'\341\200\200' = $'\341\200\200' (က)   ] Pass
  # chr_utf8         0xffff => [  $'\357\277\277' = $'\357\277\277' (���) ] Pass
  test_value_func ord_utf8     "A"           65
  test_value_func ord_utf8     "ä"          228
  test_value_func ord_utf8     $'\303\277'  255
  test_value_func ord_utf8     $'\u100'     256



  #########################################################
  #      برای مساعدت در اشکالزدایی این کد را امتحان کنید‎
  #########################################################
  printf "%q\n" $'\xff'                  # => $'\377'
  printf "%q\n" $'\uffff'                # => $'\357\277\277'
  printf "%q\n" "$(chr_utf8_echo 0x100)" # => $'\304\200'
  #
  # موقعی که تشخیص مشکلات لازم می‌شود این کد بسیار کمک می‌کند‎
  #  xterm  و(یا) برنامه read با‎
  # من در وقوع خطا زیاد از این کد برای ایجاد پیغام خطای قابل خواندن استفاده می‌کنم ‎
  # به عنوان مثال‎
  echo "Enter type to test, Enter to continue"
  while read -srN1 ; do
    ord asciiValue "${REPLY}"
    case "${asciiValue}" in
      10) echo "Goodbye" ; break ;;
      20|21|22) echo "Yay expected input" ;;
      *) printf ':( Unexpected Input 0x%02x %q "%s"\n' "${asciiValue}" "${REPLY}" "${REPLY//[[:cntrl:]]}" ;;
    esac
  done

  #########################################################
  #                    1 رویکرد عجیب و غریب‌‌تر ‎
  #########################################################
  # باید از این استفاده می‌کردم LC_CTYPE=C  من قبل از کشف رویکرد‎
  # printf "EAsciiLookup=%q" "$(for (( x=0x0; x<0x100 ; x++)); do printf '%b' $(printf '\\x%02x' "$x"); done)"
  EAsciiLookup=$'\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023'
  EAsciiLookup+=$'\024\025\026\027\030\031\032\E\034\035\036\037 !"#$%&\'()*+,-'
  EAsciiLookup+=$'./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghi'
  EAsciiLookup+=$'jklmnopqrstuvwxyz{|}~\177\200\201\202\203\204\205\206\207\210'
  EAsciiLookup+=$'\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227'
  EAsciiLookup+=$'\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246'
  EAsciiLookup+=$'\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265'
  EAsciiLookup+=$'\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304'
  EAsciiLookup+=$'\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323'
  EAsciiLookup+=$'\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342'
  EAsciiLookup+=$'\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361'
  EAsciiLookup+=$'\362\363\364\365\366\367\370\371\372\373\374\375\376\377'
  function ord_eascii2 {
    local idx="${EAsciiLookup%%${2:0:1}*}"
    eval ${1}'=$(( ${#idx} +1 ))'
  }

  #########################################################
  #                     2 رویکرد عجیب و غریب‌تر‎
  #########################################################
  #printf "EAsciiLookup2=(\n    %s\n)" "$(for (( x=0x1; x<0x100 ; x++)); do printf '%-18s'  "$(printf '[_%q]="0x%02x"' "$(printf "%b" "$(printf '\\x%02x' "$x")")" $x )" ; [ "$(($x%6))" != "0" ] || echo -en "\n    " ; done)"
  typeset -A EAsciiLookup2
  EAsciiLookup2=(
    [_$'\001']="0x01" [_$'\002']="0x02" [_$'\003']="0x03" [_$'\004']="0x04"
    [_$'\005']="0x05" [_$'\006']="0x06" [_$'\a']="0x07"   [_$'\b']="0x08"
    [_$'\t']="0x09"   [_'']="0x0a"      [_$'\v']="0x0b"   [_$'\f']="0x0c"
    [_$'\r']="0x0d"   [_$'\016']="0x0e" [_$'\017']="0x0f" [_$'\020']="0x10"
    [_$'\021']="0x11" [_$'\022']="0x12" [_$'\023']="0x13" [_$'\024']="0x14"
    [_$'\025']="0x15" [_$'\026']="0x16" [_$'\027']="0x17" [_$'\030']="0x18"
    [_$'\031']="0x19" [_$'\032']="0x1a" [_$'\E']="0x1b"   [_$'\034']="0x1c"
    [_$'\035']="0x1d" [_$'\036']="0x1e" [_$'\037']="0x1f" [_\ ]="0x20"
    [_\!]="0x21"      [_\"]="0x22"      [_\#]="0x23"      [_\$]="0x24"
    [_%]="0x25"       [_\&]="0x26"      [_\']="0x27"      [_\(]="0x28"
    [_\)]="0x29"      [_\*]="0x2a"      [_+]="0x2b"       [_\,]="0x2c"
    [_-]="0x2d"       [_.]="0x2e"       [_/]="0x2f"       [_0]="0x30"
    [_1]="0x31"       [_2]="0x32"       [_3]="0x33"       [_4]="0x34"
    [_5]="0x35"       [_6]="0x36"       [_7]="0x37"       [_8]="0x38"
    [_9]="0x39"       [_:]="0x3a"       [_\;]="0x3b"      [_\<]="0x3c"
    [_=]="0x3d"       [_\>]="0x3e"      [_\?]="0x3f"      [_@]="0x40"
    [_A]="0x41"       [_B]="0x42"       [_C]="0x43"       [_D]="0x44"
    [_E]="0x45"       [_F]="0x46"       [_G]="0x47"       [_H]="0x48"
    [_I]="0x49"       [_J]="0x4a"       [_K]="0x4b"       [_L]="0x4c"
    [_M]="0x4d"       [_N]="0x4e"       [_O]="0x4f"       [_P]="0x50"
    [_Q]="0x51"       [_R]="0x52"       [_S]="0x53"       [_T]="0x54"
    [_U]="0x55"       [_V]="0x56"       [_W]="0x57"       [_X]="0x58"
    [_Y]="0x59"       [_Z]="0x5a"       [_\[]="0x5b"      #[_\\]="0x5c"
    #[_\]]="0x5d"
                      [_\^]="0x5e"      [__]="0x5f"       [_\`]="0x60"
    [_a]="0x61"       [_b]="0x62"       [_c]="0x63"       [_d]="0x64"
    [_e]="0x65"       [_f]="0x66"       [_g]="0x67"       [_h]="0x68"
    [_i]="0x69"       [_j]="0x6a"       [_k]="0x6b"       [_l]="0x6c"
    [_m]="0x6d"       [_n]="0x6e"       [_o]="0x6f"       [_p]="0x70"
    [_q]="0x71"       [_r]="0x72"       [_s]="0x73"       [_t]="0x74"
    [_u]="0x75"       [_v]="0x76"       [_w]="0x77"       [_x]="0x78"
    [_y]="0x79"       [_z]="0x7a"       [_\{]="0x7b"      [_\|]="0x7c"
    [_\}]="0x7d"      [_~]="0x7e"       [_$'\177']="0x7f" [_$'\200']="0x80"
    [_$'\201']="0x81" [_$'\202']="0x82" [_$'\203']="0x83" [_$'\204']="0x84"
    [_$'\205']="0x85" [_$'\206']="0x86" [_$'\207']="0x87" [_$'\210']="0x88"
    [_$'\211']="0x89" [_$'\212']="0x8a" [_$'\213']="0x8b" [_$'\214']="0x8c"
    [_$'\215']="0x8d" [_$'\216']="0x8e" [_$'\217']="0x8f" [_$'\220']="0x90"
    [_$'\221']="0x91" [_$'\222']="0x92" [_$'\223']="0x93" [_$'\224']="0x94"
    [_$'\225']="0x95" [_$'\226']="0x96" [_$'\227']="0x97" [_$'\230']="0x98"
    [_$'\231']="0x99" [_$'\232']="0x9a" [_$'\233']="0x9b" [_$'\234']="0x9c"
    [_$'\235']="0x9d" [_$'\236']="0x9e" [_$'\237']="0x9f" [_$'\240']="0xa0"
    [_$'\241']="0xa1" [_$'\242']="0xa2" [_$'\243']="0xa3" [_$'\244']="0xa4"
    [_$'\245']="0xa5" [_$'\246']="0xa6" [_$'\247']="0xa7" [_$'\250']="0xa8"
    [_$'\251']="0xa9" [_$'\252']="0xaa" [_$'\253']="0xab" [_$'\254']="0xac"
    [_$'\255']="0xad" [_$'\256']="0xae" [_$'\257']="0xaf" [_$'\260']="0xb0"
    [_$'\261']="0xb1" [_$'\262']="0xb2" [_$'\263']="0xb3" [_$'\264']="0xb4"
    [_$'\265']="0xb5" [_$'\266']="0xb6" [_$'\267']="0xb7" [_$'\270']="0xb8"
    [_$'\271']="0xb9" [_$'\272']="0xba" [_$'\273']="0xbb" [_$'\274']="0xbc"
    [_$'\275']="0xbd" [_$'\276']="0xbe" [_$'\277']="0xbf" [_$'\300']="0xc0"
    [_$'\301']="0xc1" [_$'\302']="0xc2" [_$'\303']="0xc3" [_$'\304']="0xc4"
    [_$'\305']="0xc5" [_$'\306']="0xc6" [_$'\307']="0xc7" [_$'\310']="0xc8"
    [_$'\311']="0xc9" [_$'\312']="0xca" [_$'\313']="0xcb" [_$'\314']="0xcc"
    [_$'\315']="0xcd" [_$'\316']="0xce" [_$'\317']="0xcf" [_$'\320']="0xd0"
    [_$'\321']="0xd1" [_$'\322']="0xd2" [_$'\323']="0xd3" [_$'\324']="0xd4"
    [_$'\325']="0xd5" [_$'\326']="0xd6" [_$'\327']="0xd7" [_$'\330']="0xd8"
    [_$'\331']="0xd9" [_$'\332']="0xda" [_$'\333']="0xdb" [_$'\334']="0xdc"
    [_$'\335']="0xdd" [_$'\336']="0xde" [_$'\337']="0xdf" [_$'\340']="0xe0"
    [_$'\341']="0xe1" [_$'\342']="0xe2" [_$'\343']="0xe3" [_$'\344']="0xe4"
    [_$'\345']="0xe5" [_$'\346']="0xe6" [_$'\347']="0xe7" [_$'\350']="0xe8"
    [_$'\351']="0xe9" [_$'\352']="0xea" [_$'\353']="0xeb" [_$'\354']="0xec"
    [_$'\355']="0xed" [_$'\356']="0xee" [_$'\357']="0xef" [_$'\360']="0xf0"
    [_$'\361']="0xf1" [_$'\362']="0xf2" [_$'\363']="0xf3" [_$'\364']="0xf4"
    [_$'\365']="0xf5" [_$'\366']="0xf6" [_$'\367']="0xf7" [_$'\370']="0xf8"
    [_$'\371']="0xf9" [_$'\372']="0xfa" [_$'\373']="0xfb" [_$'\374']="0xfc"
    [_$'\375']="0xfd" [_$'\376']="0xfe" [_$'\377']="0xff"
  )
  function ord_eascii3 {
        local -i val="${EAsciiLookup2["_${2:0:1}"]-}"
        if [ "${val}" -eq 0 ]; then
                case "${2:0:1}" in
                        ])  val=0x5d ;;
                        \\) val=0x5c ;;
                esac
        fi
        eval "${1}"'="${val}"'
  }
  # برای تفنن موارد زیر را بررسی کنید
  time for (( i=0 ; i <1000; i++ )); do ord TmpVar 'a'; done
  #  real 0m0.065s
  #  user 0m0.048s
  #  sys  0m0.000s

  time for (( i=0 ; i <1000; i++ )); do ord_eascii TmpVar 'a'; done
  #  real 0m0.239s
  #  user 0m0.188s
  #  sys  0m0.000s

  time for (( i=0 ; i <1000; i++ )); do ord_utf8 TmpVar 'a'; done
  #  real       0m0.225s
  #  user       0m0.180s
  #  sys        0m0.000s

  time for (( i=0 ; i <1000; i++ )); do ord_eascii2 TmpVar 'a'; done
  #  real 0m1.507s
  #  user 0m1.056s
  #  sys  0m0.012s

  time for (( i=0 ; i <1000; i++ )); do ord_eascii3 TmpVar 'a'; done
  #  real 0m0.147s
  #  user 0m0.120s
  #  sys  0m0.000s

  time for (( i=0 ; i <1000; i++ )); do ord_echo 'a' >/dev/null ; done
  #  real       0m0.065s
  #  user       0m0.044s
  #  sys        0m0.016s

  time for (( i=0 ; i <1000; i++ )); do ord_eascii_echo 'a' >/dev/null ; done
  #  real       0m0.089s
  #  user       0m0.068s
  #  sys        0m0.008s

  time for (( i=0 ; i <1000; i++ )); do ord_utf8_echo 'a' >/dev/null ; done
  #  real       0m0.226s
  #  user       0m0.172s
  #  sys        0m0.012s

پرسش و پاسخ 71 (آخرین ویرایش ‎2012-03-14 06:44:55‎ توسط rgnb-4d0d6130)


Unix timestamp


چطور می‌توانم زمان یونیکس(epoch) را به مقادیر قابل خواندن انسانی تبدیل نمایم؟

تنها روش سالم مدیریت مقادیر زمان در داخل یک برنامه، تبدیل آنها به مقیاس خطی است. شما نمی‌توانید ‎"January 17, 2005 at 5:37 PM"‎ را در متغیری ذخیره کنید و انتظار انجام کاری را با آن داشته باشید....

بنابراین، هر برنامه کارآمد از نشانه‌های زمان با معانی از قبیل «تعداد ثانیه‌های از نقطه X» استفاده می‌کند . اینها را نشانه‌ها زمان epoch می‌نامند. اگر epoch نیمه شب اول ژانویه 1970 بر اساس UTC زیرنویس 1 باشد، آنوقت "Unix timestamp" نیز نامیده می‌شود، زیرا این روشی است که یونیکس تمام زمانها(ازقبیل زمان ویرایش فایل) را ذخیره می‌کند.

یونیکس استاندارد، متأسفانه ابزاری برای کار کردن با نشانه‌های زمان یونیکس ندارد. فرمان date گنو و اخیراً BSD، دارای یک الحاقیه ‎%s‎ برای تولید خروجی در قالب نشانه زمان یونیکس می‌باشند:

   # GNU/BSD date
   date +%s    #  1358612347 زمان فعلی را با قالب یونیکس چاپ می‌کند به عنوان مثال

موقعی که نیاز به فاصله زمانی بین دو رویداد باشد، این گزینه به طور رایج در اسکریپت‌ها به کار می‌رود:

   # POSIX shell, with GNU/BSD date
   start=$(date +%s)
   ...
   end=$(date +%s)
   echo "Operation took $(($end - $start)) seconds."

حال، برای تبدیل آن نشانه‌های زمان یونیکس به مقادیر قابل خواندن انسانی، استفاده از یک برنامه خارجی لازم است. یک شیوه، به کار بردن ترفندی با استفاده از date گنو است:

   # GNU date
   date -d "1970-01-01 UTC + 1358612347 seconds"
   # .را نسبت به وقت محلی تهران چاپ می‌کند Sat Jan 19 19:49:07 IRST 2013.

خواندن ‎info date‎ بخش ‎(GNU coreutils:Date input formats)‎ روشن می‌کند که این فرمان نشانه‌های زمانِ یونیکسِ پیشوند شده با '@' را می‌پذیرد، اینطور:

   # recent GNU date
   $ date -d "@1164128484"
   # .را نسبت به وقت منطقه اروپای مرکزی چاپ می‌کند "Tue Nov 21 18:01:24 CET 2006" 

به هر حال، این ویژگی فقط با نگارشهای جدیدتر date گنو کار می‌کند -- ‎coreutils 5.3.0‎ و بالاتر.

اگر شما date گنو را در دسترس ندارید، می‌توانید از پرل استفاده کنید:

   perl -le "print scalar localtime 1358612347"
   # را چاپ می‌کند Sat Jan 19 19:49:07 2013

من در این مثالها نقل‌قول دوگانه را به کار بردم به طوری که زمان ثابت می‌توانست با یک متغیر مرجع تعویض گردد. برای اطلاعات بیشتر در خصوص تغییر قالب خروجی، مستندات ‎date(1)‎ و پرل را ببینید.

نگارشهای جدیدتر Tcl (همچون 8.5) پشتیبانی مناسبی از توابع تاریخ و ساعت دارند. صفحه ‎man tclsh‎ را برای جزئیات نحوه کاربرد آن ملاحظه نمایید. برای مثال:

   echo 'puts [clock format [clock scan "today"]]' | tclsh
   # (تنظیم شودclock format تاریخ امروز را چاپ می‌کند(قالب می‌تواند با پارامترها در
   
   echo 'puts [clock format [clock scan "fortnight"]]' | tclsh
   # .تاریخ دو هفته قبل را چاپ می‌کند
   
   echo 'puts [clock format [clock scan "5 years + 6 months ago"]]' | tclsh
   # ‏۵/۵ سال قبل با احتساب سال کبیسه و زمان روشنایی روز

یک روش مناسب برای محاسبه ثانیه‌های سپری شده از ‎'YYYY MM DD HH MM SS'‎ استفاده از awk می‌باشد.

   echo "2008 02 27 18 50 23" | awk '{print systime() - mktime($0)}'
   # استفاده می‌کند epoch برای باز گرداندن زمان فعلی در شکل systime() این کُد از ‎ 
   # آن اجرا می‌کند epoch را روی رشته ورودی برای به دست آوردن زمان mktime() سپس

برای آنکه خواندن آن توسط انسان خواناتر گردد، می‌توان از awk گنو (gawk) استفاده نمود: قالب‌بندی رشته در آن مشابه با date است، و به طور دقیق در توابع زمان در gawk نشان داده شده است

 echo "YYYY MM DD HH MM SS" | gawk '{print strftime("%M Minutes, %S Seconds",systime() - mktime($0))}'
 # تفاضل را به یک شکل قابل خواندن انسانی تبدیل می‌کند ،gawk مخصوص strftime() تابع 

پرسش و پاسخ 70 (آخرین ویرایش ‎2013-04-10 21:27:34‎ توسط geirha)


  1. مترجم: ‎UTC برگرفته از Universal Time Coordinated‎ است که روش مدرن و دقیقتر از GMT(وقت گرینویچ) برای محاسبه یکنواخت زمان در تمام نقاط جهان است و ساعت اتمی بین‌المللی نیز گفته می‌شود. (1)


ارسال کلمه عبور!


می‌خواهم یک ارتباط ssh (یا scp، یا sftp) را خودکار نمایم، اما نمی‌دانم چطور کلمه عبور را ارسال کنم

ایست!

اول از همه، اگر شما واقعاً کلمه عبور خود را در جایی از اسکریپت تعبیه کنید، می‌تواند در تمام جهان قابل رؤیت بشود(یا حداقل، برای هر شخصی که بتواند فایلهای سیستم شما را بخواند). این امر تمامی هدف از داشتن کلمه عبور برای حساب راه دور شما را بر باد می‌دهد.

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

مخصوصاً، خودتان از کاربر کلمه عبورش را نپرسید که در یک اسکریپت ذخیره و سپس ارسال آن به ssh را آزمایش کنید. این کار به شدت امنیت شما را کاهش می‌دهد.

اگر می‌خواهید به طورکلی کلمه عبور تأیید اعتبار را کنار بگذارید، آنوقت به جای آن باید از public key authentication(کلید عمومی تصدیق اعتبار) استفاده کنید. صفحه man در مورد ‎ssh-keygen(1)‎ را بخوانید و بفهمید، یا برای یک مرور کوتاه، SshKeys را ببینید. این صفحه به شما می‌گوید که چگونه یک زوج کلید عمومی و خصوصی تولید کنید(در یکی از قالب‌های RSA 1 یا DSA )، و چطور از این کلیدها بدون ارسال هیچ کلمه عبوری برای تصدیق هویت در سیستم راه دور استفاده کنید.

این هم یک خلاصه فشرده از طرز کار:

ssh-keygen -t rsa
ssh me@remote "cat >> ~/.ssh/authorized_keys" < ~/.ssh/id_rsa.pub
ssh me@remote date     # اعلان ورود کلمه عبور نمی‌دهد‎
                       # اما کلید شما می‌تواند یک عبارت عبور داشته باشد

اگر کلید شما شامل یک عبارت عبور باشد، و شما می‌خواهید از تایپ آن در هر نوبت اجتناب کنید، ‎ssh-agent(1)‎ را بررسی کنید. به هر حال این موضوع فراتر از محدوده این نوشته است. اگر اسکریپت شما باید به طور خودکار اجرا شود، آنوقت لازم است شما عبارت عبور را از کلید پاک کنید. این کار امنیت شما را کاهش می‌دهد، به علت آنکه بعد شخصی که کلید را برباید می‌تواند با عنوان شما به سرویس‌دهنده راه دور متصل شود( این معادل قرار دادن کلمه عبور در یک فایل است). اگر چه، گاهی اوقات با یک ریسک قابل قبول این کار صلاح دانسته می‌شود.

اگر حتی با یک کلید عمومی درج شده در فایل authorized_keys راه دور، به شما اعلان کلمه عبور داده می‌شود ،احتمال می‌رود شما مشکل مجوزها در سیستم راه دور دارید. برای بحث در مورد این قبیل مشکلات SshKeys را ملاحظه کنید.

اگر اینطور نیست، پس مطمئن شوید که املای آن به صورت authorised_keys نباشد. SSH از املای US به صورت authorized_keys استفاده می‌کند.

اگر شما واقعاً می‌خواهید به جای استفاده از کلیدهای عمومی، کلمه عبور را در یک متغیر ذخیره کنید و بعد آن را به برنامه‌ای عبور بدهید، اول ببین آفتاب به سرت نتابیده. آنوقت، اگر , بازهم می‌خواهید از کلمه عبور استفاده کنید، ‎expect(1)‎ را به کار ببرید (یا ‎empty(1)‎ کمتر کلاسیک اما بیشتر موافق bash). اما از ما برای کمک در مورد آن نپرسید.

expect همچنین در انواع متفاوت مربوط به telnet یا FTP این پرسش صدق می‌کند. با این وجود هرکس که هنوز هم بدون یک دلیل خوب telnetd را اجرا می‌کند، لازم است اخراج و جایگزین بشود.


پرسش و پاسخ 69 (آخرین ویرایش ‎2011-11-08 14:23:33‎ توسط pgas)


  1. مترجم: RSA نام متداولترین الگوریتم تهیه کلید عمومی و کلید خصوصی رمزنگاری می‌باشد، که از حروف اول نام ابداع کنندگان این روش اخذ گردیده است که سه نفر به نام‌های ‎Ron Rivest , Adi Shamir , Leonard Adleman‎ می‌باشند، ایشان در سال 1977 این شیوه رمزنگاری را ابداع نمودند، امنیت RSA به استناد دشواری یافتن عوامل مؤثر در تولید اعداد خیلی بزرگ می‌باشد. در حال حاضر این دشواری، امنیت لازم را تامین می‌نماید اما ممکن است در آینده هکرها بتوانند روش آسانی برای غلبه بر آن ابداع کنند! شایان ذکر است که حق امتیاز RSA متعلق به شرکت امنیتی با همین نام بود که در سپتامبر سال 2000 منقضی گردیده است.
    روش DSA نیز که سرنام Digital Signature Algorithm می‌باشد، یک استاندارد ‎U.S. federal‎ است که در سال 1991 توسط موسسه ملی تکنولوژی و استانداردها در امریکا تهیه گردیده است.
    (بازگشت)


timeout برای انصراف از اجرای فرمان


چگونه می‌توانم فرمانی را اجرا کنم و انصراف از آن پس از N ثانیه را داشته باشم(timeout)

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

اگر فرمان هیچ پشتیبانی درونی از توقف پس از زمان تعیین شده نداشته باشد، آنوقت بهترین جایگزین‌ها، برخی برنامه‌های خارجی به نام timeout و doalarm می‌باشند. بعضی توزیع‌های لینوکس نگارش tct از timeout را به عنوان یک بسته ارائه می‌کنند. یک نگارش گنو از timeout نیز وجود دارد، که در انتشارهای اخیر coreutils ضمیمه گردیده است.

مراقب باشید: بعضی از پیاده‌سازی‌های timeout به طور پیش فرض، یک سیگنال SIGKILL ‏(‎kill -9‎) صادر می‌کنند، که تقریباً همان بیرون آوردن کابل برق است( یعنی از دست دادن هر شانس برنامه برای به انجام رساندن کارهایش که اغلب منجر به خراب شدن داده‌هایش می‌شود ). شما به جای آن باید از سیگنالی استفاده کنید که به برنامه اجازه بدهد خودش را خاموش کند ‎(SIGTERM)‎. برای اطلاعات بیشتر در باره SIGKILL، مدیریت پردازش را ملاحظه کنید.

تفاوت عمده بین doalarm و timeout آنست که doalarm برنامه را بعد از تنظیم مهلت مقرر به اجرا در می‌آورد، که در یک WrapperScript آن را شگفت‌آور می‌سازد، در حالیکه timeout برنامه را به عنوان یک فرزند شروع می‌کند و سپس همراه آن می‌ماند( هر دو پردازش به طور همزمان وجود دارند)، که به ما مجال می‌دهد در صورت لزوم بیش از یک سیگنال ارسال کنیم.

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

doalarm() { perl -e 'alarm shift; exec @ARGV' "$@"; }

doalarm ${NUMBER_OF_SECONDS_BEFORE_ALRMING} program arg arg ...

اگر شما نمی‌توانید یا نمی‌خواهید یکی از این برنامه‌ها را به کار ببرید(که به راستی در هسته اصلی ابزارهای یونیکس در 30 سال قبل از این گنجانده شده بود!)، آنوقت بهترین کاری که می‌توانید انجام بدهید، راه حل بدشکلی مانند این است:

   command & pid=$!
   { sleep 10; kill $pid; } &

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

انجام کاری مشابه آن، اما نگهداری command در پیش‌زمینه امکان‌پذیر است:

   bash -c '(sleep 10; kill $$) & exec command'

kill $$‎ پوسته را kill می‌کند، به استثنای آن exec باعث می‌شود فرمان PID پوسته را تحویل بگیرد. لازم است از ‎bash -c‎ استفاده شود برای این که پوسته فراخواننده تعویض نشود، در ‎bash 4‎، استفاده از پوسته فرعی به جای آن امکان‌پذیر است:

   ( cmdpid=$BASHPID; (sleep 10; kill $cmdpid) & exec command )

اسکریپت پوسته "timeout" (با فرمان timeout اشتباه نشود) از رویکرد دوم در بالا استفاده می‌کند. مزیت آن کارکرد فوری آن است(نیازی به کامپایل شدن ندارد)، اما مشکلاتی دارد، به عنوان مثال با برنامه‌هایی که از ورودی استاندارد می‌خوانند.

واقعاً، به جای آن فقط از timeout یا doalarm استفاده کنید.


پرسش و پاسخ 68 (آخرین ویرایش ‎2010-07-27 13:03:01‎ توسط GreyCat)


حذف زواید از متغیر


چطور می‌توانم فضای سفید قبل یا بعد یکی از متغیرهایم را پاک کنم؟

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

در اینجا یکی از آنها که فقط برای فضاهای سفید کار می‌کند، آمده است. این کُد بر این واقعیت تکیه دارد که readدر صورتی که IFS برقرار نشده باشد، تمام فضاهای سفید ابتدا و انتها را پاک می‌کند:

   # POSIX اما در صورتیکه متغیر شامل سطرجدید باشد شکست می‌خورد
   read -r var << EOF
   $var
   EOF

Bash می‌تواند کار مشابهی را با یک "here string" انجام بدهد:

   # Bash
   read  -rd '' x <<< "$x"

استفاده از یک رشته تهی به عنوان جداکننده به معنی آن است که read تمام آن رشته را از بین می‌برد، به طوریکه NUL استفاده می‌شود. (به خاطر بیاورید: BASH فقط متغیرهای رشته‌ای C به کار می‌برد.) این برای هر متنی ازجمله شامل سطرجدید مطمئن است.

این هم راه حلی با استفاده از extglob و بسط پارامتر همراه با یکدیگر:

   # Bash
   shopt -s extglob
   x=${x##+([[:space:]])} x=${x%%+([[:space:]])}

همچنین این روش در پوسته Korn بدون ضرورت تنظیم صریح extglob کار می‌کند:

   # ksh
   x=${x##+([[:space:]])} x=${x%%+([[:space:]])}

این روش آنطور که چند روش اول بودند، محدود به فضاهای سفید نیست. بعلاوه، صفرهای مقدم را می‌توانید حذف کنید:

   # Bash
   shopt -s extglob
   x=${x##+(0)}

روش دیگری در bash برای حذف صفرهای مقدم بر عدد، رفتار کردن با آنها به عنوان عدد صحیح در یک زمینه محاسباتی است:

   # Bash
   x=$((10#$x))
   # شامل هرچیز دیگری غیر از رقم باشد این روش ناموفق است x ،هر چند اگر

اگر در پوسته POSIX نیاز به پاک کردن صفرهای مقدم دارید، می‌توانید یک حلقه به کار ببرید:

   # POSIX
   while true; do
     case "$var" in
       0*) var=${var#0};;
       *)  break;;
     esac
   done

یا این ترفند( با تفصیل بیشتر در پرسش و پاسخ شماره 100 پوشش داده شده):

   # POSIX
   zeroes=${var%%[!0]*}
   var=${var#$zeroes}

بسیار بسیار روشهای دیگری برای انجام این کار وجود دارد، برای نمونه استفاده از sed:

   # POSIX, فضاهای سفید اول و انتهای هر سطر را موقوف می‌کند
   x=$(echo "$x" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')

برای بریدن زوائد فایلهای بزرگ ، راه حل‌های مبتنی بر برنامه‌های خارجی مانند sed بیشتر از متغیرهای پوسته مناسب می‌باشند.


پرسش و پاسخ 67 (آخرین ویرایش ‎ 2011-06-21 15:20:23‎ توسط GreyCat)