首页 > 解决方案 > 继续不跳过在 shell 脚本中向前迭代

问题描述

我为 bash 中的字符串创建了一个十六进制到 ASCII 转换器。我正在使用的应用程序将字符串中的字符 (除了 [0-9],[AZ],[az]) 更改为其对应的 %hexadecimal。例如:/ 更改为字符串中的 %2F

我想按原样保留 ASCII 字符。下面是我的代码:

NAME=%2fhome%40%21%23
C_NAME=""
for (( i=0; i<${#NAME}; i++ )); do
    CHK=$(echo "{NAME:$i:1}" | grep -v "\%" &> /dev/null;echo $?)
    if [[ ${CHK} -eq 0 ]]; then
       C_NAME=`echo "$C_NAME${NAME:$i:1}"`
    else
       HEX=`echo "${NAME:$i:3}" | sed "s/%//"`
       C_NAME=`echo -n "$C_NAME";printf "\x$HEX"`
       continue 2
    fi
done
echo "$C_NAME"

输出:

 /2fhome@40!21#23

预期的:

  /home@!#

所以基本上转换正在发生,但没有到位。它也保留了十六进制值,这告诉我该continue 2语句可能没有像我在代码中所期望的那样工作。请任何解决方法。

标签: bashshellunix

解决方案


使用脚本的结构进行一些简化和更正:

#!/bin/bash
name=%2fhome%40%21%23
c_name=""
for (( i=0; i<${#name}; i++ )); do
    c=${name:i:1}
    if [[ $c != % ]]; then
       c_name=$c_name$c
    else
       hex=${name:i+1:2}
       printf -v c_name "%s\x$hex" "$c_name"
       (( i += 2 ))    # stolen from Dudi Boy's answer
    fi
done
echo "$c_name"
  • 始终使用小写或混合大小写的变量,以避免名称与 shell 或环境变量发生冲突的机会
  • 始终使用$()而不是反引号
  • 您使用的大多数echo命令都不是必需的
  • 您可以避免使用sedgrep
  • 变量不应该包含在格式字符串中,printf但在这里不能轻易避免(echo -e "\x$hex"尽管您可以使用)
  • 您可以在参数扩展中进行数学运算
  • %不需要在您的grep命令中转义
  • 如果您直接使用它的值,您可以消除该$hex变量:
    printf -v c_name "%s\x${name:i+1:2}" "$c_name"

推荐阅读