我为bash中的字符串创建了一个十六进制ASCII转换器。我正在使用的应用程序将字符串中的字符([0-9],[A-Z],[a-z]以外的任何字符)更改为对应的%十六进制。例如:/更改为字符串中的%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
语句可能无法按我期望的方式工作。请采取任何解决方法。
答案 0 :(得分:2)
您只有一个循环,所以我假设您期望continue 2
跳过当前循环的当前迭代和下一个迭代,但是文档help continue
明确指出了
继续[n]
[...]
如果指定N,则恢复第N个封闭循环。
没有内置函数可以跳过当前循环的当前以及下一个循环,但是在您的情况下,您可以使用(( i += 2 ))
代替continue 2
。
答案 1 :(得分:2)
使用脚本的结构进行一些简化和更正:
#!/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"
$()
代替反引号echo
命令sed
和grep
printf
的格式字符串中,但是在这里不能轻易避免(不过您可以改用echo -e "\x$hex"
)%
不需要在您的grep
命令中转义$hex
变量的值,则可以消除它:printf -v c_name "%s\x${name:i+1:2}" "$c_name"
答案 2 :(得分:1)
我真的很喜欢你的运动,并决定用awk(我目前的研究)解决它。
希望您也喜欢它。
cat script.awk
BEGIN {RS = "%[[:xdigit:]]+"} { # redefine record separtor to RegEx (gawk specific)
decNum = strtonum("0x"substr(RT, 2)); # remove prefix # from record separator, convert hex num to dec
outputStr = outputStr""$0""sprintf("%c", decNum); # reconstruct output string
}
END {print outputStr}
输出
echo %2fhome%40%21%23 |awk -f script.awk
/home@!#