用shell进行ASCII字符转换与URL编码技巧



如何将ASCII字符转换为十进制(或十六进制)值并进行相反的转换?如何进行URL编码和URL解码?

如果你在编写脚本时已知八进制或十六进制值,你可以使用printf命令实现:

# POSIX
printf '\047\n'

# bash/ksh/zsh 和其他一些 printf 实现也支持:
printf '\x27\n'
在字符编码为ASCII的超集的地区,这将打印出单引号字符(47是撇号字符的八进制ASCII值),后面是一个换行符。十六进制版本也可以在包括bash内置在内的一些printf实现中使用,但不是标准的/POSIX的。

在bash 4.2及更高版本以及ksh93中,printf还支持Unicode代码点:

# bash 4.2, ksh93
printf '\u0027\n'

另一种方法是使用bash的#39;...'引用方法来扩展所需的字符,可以用于变量赋值或直接作为命令参数:

ExpandedString=#39;\x27\047\u0027\U00000027\n'
printf %s\\n "$ExpandedString"

# 或者更简单地
printf %s\\n #39;\x27\047\u0027\U00000027\n'

如果你需要对事先未知的字符(或数字ASCII值)进行转换(即在变量中),可以使用稍微复杂一些的方法。注意:这些函数仅适用于单字节字符编码。

# POSIX
# chr() - 将十进制值转换为ASCII字符表示
# ord() - 将ASCII字符转换为其十进制值

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

为了避免使用子shell,更好的方法是将值传递给变量而不是命令输出。这样更快,因为它避免了子shell的使用。

chr () {
  local val
  [ "$1" -lt 256 ] || return 1
  printf -v val %o "$1"; printf "\\$val"
  # 需要bash 3.1或更高版本。
}
ord() {
  # POSIX
  LC_CTYPE=C printf %d "'$1"
}

# hex() - 将ASCII字符转换为十六进制值
# unhex() - 将十六进制值转换为ASCII字符

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

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

# 示例:

chr "$(ord A)"    # -> A
ord "$(chr 65)"   # -> 65

上述的ord函数相当巧妙。

巧妙?更确切地说,它使用了一个我无法在任何地方找到文档的特性 - 在字符前面加上单引号。这是一个很不错的效果,但你是怎么知道它的呢?是源码挖掘吗?- GreyCat

它符合Single Unix规范:“如果前导字符是单引号或双引号,则值应为在单引号或双引号之后的字符的底层代码集中的数值。”(参见 printf() 了解更多)- mjf

URL编码和URL解码

请注意,URL编码仅在字节(八位)级别上定义。对多字节(例如UTF-8)字符进行URL编码仅需要对每个字节进行单独编码,然后将其连接起来。

还请注意,下面的urldecode函数不执行错误检查。如果输入的数据不正确,如何生成有意义的错误消息是留给读者的练习。

urlencode() {
    # urlencode <string>
    local LC_ALL=C c i n
    for (( i = 0, n = ${#1}; i < n; i++ )); do
        c=${1:i:1}
        case $c in
            [[:alnum:].~_-]) printf %s "$c" ;;
            *) printf %%%02X "'$c"  ;;
        esac
    done
}
urldecode() {
    # urldecode <string>
    local s
    s=${1//\\/\\\\}
    s=${s//+/ }
    printf %b "${s//'%'/\\x}"
}
# 或者使用另一种urlencode方式,一次性打印所有字符(需要bash 3.1)

urlencode() {
    # urlencode <string>
    local LC_ALL=C c i n=${#1}
    local out= tmp
    for (( i=0; i < n; i++ )); do
        c=${1:i:1}
        case $c in
            [[:alnum:].~_-]) printf -v tmp %s "$c" ;;
            *) printf -v tmp %%%02X "'$c"  ;;
        esac
        out+=$tmp
    done
    printf %s "$out"
}

更完整的示例(带有UTF-8支持)

命令行实用程序nkf可以解码URL:

echo 'https://ja.wikipedia.org/wiki/%E9%87%8E%E8%89%AF%E7%8C%AB' | nkf --url-input

关于扩展ASCII和UTF-8编码的注意事项

以下示例从未经过同行评审。每个人都对它感到恐惧。请自行决定是否继续。

  • 对于值0x00 - 0x7f,结果相同。
  • 对于值0x80 - 0xff,UTF-8和扩展ASCII之间有冲突。
  • 对于值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 family
  ###########################################################################
  # ord          <返回变量名称> <要转换的字符> [可选格式字符串]
  # ord_hex      <返回变量名称> <要转换的字符>
  # ord_oct      <返回变量名称> <要转换的字符>
  # ord_utf8     <返回变量名称> <要转换的字符> [可选格式字符串]
  # ord_eascii   <返回变量名称> <要转换的字符> [可选格式字符串]
  # ord_echo                       <要转换的字符> [可选格式字符串]
  # ord_hex_echo                   <要转换的字符>
  # ord_oct_echo                   <要转换的字符>
  # ord_utf8_echo                  <要转换的字符> [可选格式字符串]
  # ord_eascii_echo                <要转换的字符> [可选格式字符串]
  #
  # 描述:
  # 将使用本地编码的字符转换为十进制值,并存储在指定的变量中。
  # 将其存储在指定的变量中
  #
  #       ord
  #       ord_hex         以十六进制输出
  #       ord_oct         以八进制输出
  #       ord_utf8        强制使用UTF8解码
  #       ord_eascii      强制使用eascii解码
  #       ord_echo        输出到标准输出流(stdout)
  #       ord_hex_echo    以十六进制输出并输出到标准输出流(stdout)
  #       ord_oct_echo    以八进制输出并输出到标准输出流(stdout)
  #       ord_utf8_echo   强制使用UTF8解码并输出到标准输出流(stdout)
  #       ord_eascii_echo 强制使用eascii解码并输出到标准输出流(stdout)
  function ord {
          printf -v "${1?Missing Dest Variable}" "${3:-%d}" "'${2?Missing Char}"
  }
  function ord_oct {
          ord "${@:1:2}" "0%c"
  }
  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 family
  ###########################################################################
  # 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编码
  #       chr_eascii              强制使用eascii编码
  #       chr_echo                输出到标准输出流(stdout)
  #
  function chr_utf8_m {
    local val
    #
    # bash仅从4.2版本开始支持\u \U

    # 下面是一个如何编码的示例
    # 手动
    # 自Bash 3.1起,它使用-v选项进行了改进
    #
    if [[ ${2:?Missing Ordinal Value} -le 0x7f ]]; then
      printf -v val "\\%03o" "${2}"
    elif [[ ${2} -le 0x7ff        ]]; then
      printf -v val "\\%03o" \
        $((  (${2}>> 6)      |0xc0 )) \
        $(( ( ${2}     &0x3f)|0x80 ))
    elif [[ ${2} -le 0xffff       ]]; then
      printf -v val "\\%03o" \
        $(( ( ${2}>>12)      |0xe0 )) \
        $(( ((${2}>> 6)&0x3f)|0x80 )) \
        $(( ( ${2}     &0x3f)|0x80 ))
    elif [[ ${2} -le 0x1fffff     ]]; then
      printf -v val "\\%03o"  \
        $(( ( ${2}>>18)      |0xf0 )) \
        $(( ((${2}>>12)&0x3f)|0x80 )) \
        $(( ((${2}>> 6)&0x3f)|0x80 )) \
        $(( ( ${2}     &0x3f)|0x80 ))
    elif [[ ${2} -le 0x3ffffff    ]]; then
      printf -v val "\\%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"  \
        $(( ( ${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 编码错误
 		 #  \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 {
	  # 去除前导的0,否则被解释为八进制
  	  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 编码错误
                  # \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是一个数字字符串
	  # so 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 {
	# 去除前导的0,
	# 否则被解释为八进制
          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    => [      #39;\303\266' = #39;\303\266'     (ö)  ] Pass
  # chr                  65     => [                A = A               (A)   ] Pass
  # ord                  A      => [               65 = 65              (65)  ] Pass
  # chr                  246    => [      #39;\303\266' = #39;\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   #39;\xff'
  test_value_func chr_eascii   0xff   #39;\xff'
  test_value_func chr_utf8     0xff   #39;\uff'      # Note this fails because bash encodes it incorrectly
  test_value_func chr_utf8     0xff   #39;\303\277'
  test_value_func chr_utf8     0x100  #39;\u100'
  test_value_func chr_utf8     0x1000 #39;\u1000'
  test_value_func chr_utf8     0xffff #39;\uffff'
  # chr_eascii           0xff   => [          #39;\377' = #39;\377'         (�)   ] Pass
  # chr_utf8             0xff   => [      #39;\303\277' = #39;\377'         (�)   ] Fail
  # chr_utf8             0xff   => [      #39;\303\277' = #39;\303\277'     (ÿ)  ] Pass
  # chr_utf8             0x100  => [      #39;\304\200' = #39;\304\200'     (Ā)  ] Pass
  # chr_utf8             0x1000 => [  #39;\341\200\200' = #39;\341\200\200' (က) ] Pass
  # chr_utf8             0xffff => [  #39;\357\277\277' = #39;\357\277\277' (���) ] Pass
  test_value_func ord_utf8     "A"           65
  test_value_func ord_utf8     "ä"          228
  test_value_func ord_utf8     #39;\303\277'  255
  test_value_func ord_utf8     #39;\u100'     256

  #########################################################
  # 用于帮助调试问题的代码段
  #########################################################
  printf "%q\n" #39;\xff'                  # => #39;\377'
  printf "%q\n" #39;\uffff'                # => #39;\357\277\277'
  printf "%q\n" "$(chr_utf8_echo 0x100)" # => #39;\304\200'
  #
  # 这对诊断问题有很大帮助
  # 读取或 xterm 程序的输出结果
  # 我经常在出错情况下使用它来创建人类可读的错误信息
  # 例如:
  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=#39;\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023'
  EAsciiLookup+=#39;\024\025\026\027\030\031\032\E\034\035\036\037 !"#$%&\'()*+,-'
  EAsciiLookup+=#39;./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghi'
  EAsciiLookup+=#39;jklmnopqrstuvwxyz{|}~\177\200\201\202\203\204\205\206\207\210'
  EAsciiLookup+=#39;\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227'
  EAsciiLookup+=#39;\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246'
  EAsciiLookup+=#39;\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265'
  EAsciiLookup+=#39;\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304'
  EAsciiLookup+=#39;\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323'
  EAsciiLookup+=#39;\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342'
  EAsciiLookup+=#39;\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361'
  EAsciiLookup+=#39;\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=(
    [_#39;\001']="0x01" [_#39;\002']="0x02" [_#39;\003']="0x03" [_#39;\004']="0x04"
    [_#39;\005']="0x05" [_#39;\006']="0x06" [_#39;\a']="0x07"   [_#39;\b']="0x08"
    [_#39;\t']="0x09"   [_'']="0x0a"      [_#39;\v']="0x0b"   [_#39;\f']="0x0c"
    [_#39;\r']="0x0d"   [_#39;\016']="0x0e" [_#39;\017']="0x0f" [_#39;\020']="0x10"
    [_#39;\021']="0x11" [_#39;\022']="0x12" [_#39;\023']="0x13" [_#39;\024']="0x14"
    [_#39;\025']="0x15" [_#39;\026']="0x16" [_#39;\027']="0x17" [_#39;\030']="0x18"
    [_#39;\031']="0x19" [_#39;\032']="0x1a" [_#39;\E']="0x1b"   [_#39;\034']="0x1c"
    [_#39;\035']="0x1d" [_#39;\036']="0x1e" [_#39;\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"       [_#39;\177']="0x7f" [_#39;\200']="0x80"
    [_#39;\201']="0x81" [_#39;\202']="0x82" [_#39;\203']="0x83" [_#39;\204']="0x84"
    [_#39;\205']="0x85" [_#39;\206']="0x86" [_#39;\207']="0x87" [_#39;\210']="0x88"
    [_#39;\211']="0x89" [_#39;\212']="0x8a" [_#39;\213']="0x8b" [_#39;\214']="0x8c"
    [_#39;\215']="0x8d" [_#39;\216']="0x8e" [_#39;\217']="0x8f" [_#39;\220']="0x90"
    [_#39;\221']="0x91" [_#39;\222']="0x92" [_#39;\223']="0x93" [_#39;\224']="0x94"
    [_#39;\225']="0x95" [_#39;\226']="0x96" [_#39;\227']="0x97" [_#39;\230']="0x98"
    [_#39;\231']="0x99" [_#39;\232']="0x9a" [_#39;\233']="0x9b" [_#39;\234']="0x9c"
    [_#39;\235']="0x9d" [_#39;\236']="0x9e" [_#39;\237']="0x9f" [_#39;\240']="0xa0"
    [_#39;\241']="0xa1" [_#39;\242']="0xa2" [_#39;\243']="0xa3" [_#39;\244']="0xa4"
    [_#39;\245']="0xa5" [_#39;\246']="0xa6" [_#39;\247']="0xa7" [_#39;\250']="0xa8"
    [_#39;\251']="0xa9" [_#39;\252']="0xaa" [_#39;\253']="0xab" [_#39;\254']="0xac"
    [_#39;\255']="0xad" [_#39;\256']="0xae" [_#39;\257']="0xaf" [_#39;\260']="0xb0"
    [_#39;\261']="0xb1" [_#39;\262']="0xb2" [_#39;\263']="0xb3" [_#39;\264']="0xb4"
    [_#39;\265']="0xb5" [_#39;\266']="0xb6" [_#39;\267']="0xb7" [_#39;\270']="0xb8"
    [_#39;\271']="0xb9" [_#39;\272']="0xba" [_#39;\273']="0xbb" [_#39;\274']="0xbc"
    [_#39;\275']="0xbd" [_#39;\276']="0xbe" [_#39;\277']="0xbf" [_#39;\300']="0xc0"
    [_#39;\301']="0xc1" [_#39;\302']="0xc2" [_#39;\303']="0xc3" [_#39;\304']="0xc4"
    [_#39;\305']="0xc5" [_#39;\306']="0xc6" [_#39;\307']="0xc7" [_#39;\310']="0xc8"
    [_#39;\311']="0xc9" [_#39;\312']="0xca" [_#39;\313']="0xcb" [_#39;\314']="0xcc"
    [_#39;\315']="0xcd" [_#39;\316']="0xce" [_#39;\317']="0xcf" [_#39;\320']="0xd0"
    [_#39;\321']="0xd1" [_#39;\322']="0xd2" [_#39;\323']="0xd3" [_#39;\324']="0xd4"
    [_#39;\325']="0xd5" [_#39;\326']="0xd6" [_#39;\327']="0xd7" [_#39;\330']="0xd8"
    [_#39;\331']="0xd9" [_#39;\332']="0xda" [_#39;\333']="0xdb" [_#39;\334']="0xdc"
    [_#39;\335']="0xdd" [_#39;\336']="0xde" [_#39;\337']="0xdf" [_#39;\340']="0xe0"
    [_#39;\341']="0xe1" [_#39;\342']="0xe2" [_#39;\343']="0xe3" [_#39;\344']="0xe4"
    [_#39;\345']="0xe5" [_#39;\346']="0xe6" [_#39;\347']="0xe7" [_#39;\350']="0xe8"
    [_#39;\351']="0xe9" [_#39;\352']="0xea" [_#39;\353']="0xeb" [_#39;\354']="0xec"
    [_#39;\355']="0xed" [_#39;\356']="0xee" [_#39;\357']="0xef" [_#39;\360']="0xf0"
    [_#39;\361']="0xf1" [_#39;\362']="0xf2" [_#39;\363']="0xf3" [_#39;\364']="0xf4"
    [_#39;\365']="0xf5" [_#39;\366']="0xf6" [_#39;\367']="0xf7" [_#39;\370']="0xf8"
    [_#39;\371']="0xf9" [_#39;\372']="0xfa" [_#39;\373']="0xfb" [_#39;\374']="0xfc"
    [_#39;\375']="0xfd" [_#39;\376']="0xfe" [_#39;\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

更多

了解更多shell的更多编程技巧和编程最佳实践,可以关注我正在编写的《shell脚本编程最佳实践》

举报
评论 0