使用 awk printf 对文本进行 urldecode

Posted

技术标签:

【中文标题】使用 awk printf 对文本进行 urldecode【英文标题】:Using awk printf to urldecode text 【发布时间】:2011-04-13 06:50:58 【问题描述】:

我正在使用awk 对一些文本进行urldecode。

如果我将字符串编码到printf 语句中,例如printf "%s", "\x3D",它会正确输出=。如果我将整个转义字符串作为变量,则相同。

但是,如果我只有3D,我怎么能附加\x 所以printf 将打印= 而不是\x3D

我正在使用busybox awk 1.4.2ash shell。

【问题讨论】:

【参考方案1】:

我不知道你是如何在 awk 中做到这一点的,但在 perl 中是微不足道的:

echo "http://example.com/?q=foo%3Dbar" | 
    perl -pe 's/\+/ /g; s/%([0-9a-f]2)/chr(hex($1))/eig'

【讨论】:

谢谢,但是 perl 不可用。 @zwol 如果您使用反斜杠转义 +,这仅适用于 Perl 5!顺便说一句,完全没有 s/\+/ /g 部分的示例 URL 对我来说很好用!单独的第二个正则表达式已经可以解决问题了。 @syntaxerror 你说的很对 + 需要转义,不知道我是怎么错过的。我认为?q=phrase+separated+by+plus+signs 符号自从我写这篇文章以来已经不那么常见了,但它仍然是spec for application/x-www-form-urlencoded 表单提交转义的一部分。 哦,你是对的,我忘记了那些表单提交。但是,由于我的主要目标是修复“乱码”下载链接,所以最重要的是首先摆脱所有这些 %20%3D%3F(等)的东西。【参考方案2】:

由于您使用的是 ash 而 Perl 不可用,我假设您可能没有 gawk

对我来说,使用 gawkbusybox awk,您的第二个示例与第一个示例的工作方式相同(我从两者都得到“=”),除非我使用 --posix 选项(其中如果我得到 both 的“x3D”)。

如果我将--non-decimal-data--traditionalgawk 一起使用,我会得到“=”。

您使用的是什么版本的 AWK(awknawkgawk、busybox - 和版本号)?

编辑:

您可以通过添加零将变量的字符串值强制转换为数字:

~/busybox/awk 'BEGIN  string="3D"; pre="0x"; hex=pre string; printf "%c", hex+0'

【讨论】:

你说得对,它确实有效。我问错了问题 - 我会修改它。 (我使用的是busybox awk,版本1.4.2) 我花了很长时间才意识到这个单行代码仅适用于 one 变量,没有完整的 urlencoded 字符串(例如,用 %20%3F 填充的网址东西)【参考方案3】:

GNU awk

#!/usr/bin/awk -fn
@include "ord"
BEGIN 
  RS = "%.."


  printf RT ? $0 chr("0x" substr(RT, 2)) : $0

或者

#!/bin/sh
awk -niord 'printf RT?$0chr("0x"substr(RT,2)):$0' RS=%..

Decoding URL encoding (percent encoding)

【讨论】:

这是乱码,例如UTF-8 编码的非 ASCII 字符【参考方案4】:

这依赖于 gnu awk 对 split 函数的扩展,但这是可行的:

gawk ' numElems = split($0, arr, /%../, seps);
        outStr = ""
        for (i = 1; i <= numElems - 1; i++) 
            outStr = outStr arr[i]
            outStr = outStr sprintf("%c", strtonum("0x" substr(seps[i],2)))
        
        outStr = outStr arr[i]
        print outStr
      '

【讨论】:

【参考方案5】:

首先,我知道这是一个老问题,但没有一个答案对我有用(仅限于 busybox awk)

两个选项。解析标准输入:

awk 'for (y=0;y<127;y++) if (y!=37) gsub(sprintf("%%%02x|%%%02X",y,y), y==38 ? "\\&" : sprintf("%c", y));gsub(/%25/, "%");print'

获取命令行参数:

awk 'BEGIN for (y=0;y<127;y++) if (y!=37) gsub(sprintf("%%%02x|%%%02X",y,y), y==38 ? "\\&" : sprintf("%c", y), ARGV[1]);gsub(/%25/, "%", ARGV[1]);print ARGV[1]' parameter

必须最后执行 %25,否则像 %253D 这样的字符串会被双重解析,这是不应该发生的。

y==38 的内联检查是因为 gsub 将 & 视为特殊字符,除非您使用反斜杠。

【讨论】:

以上是关于使用 awk printf 对文本进行 urldecode的主要内容,如果未能解决你的问题,请参考以下文章

Linux常用基本命令:三剑客命令之-awk格式化动作

使用awk格式化输出文本

Linux上文本三剑客之awk详解

文本处理工具awk

awk 总结

AWK的使用