如何使用 unix 实用程序将所有转义序列替换为非转义等效项 (sed/tr/awk)

How to replace all escape sequences with non-escaped equivalent with unix utilities (sed/tr/awk)

我正在处理用于显示过滤器的 Wireshark 配置文件 (dfilter_buttons),并希望打印出给定名称的过滤器。文件内容如下:

示例输入

"TRUE","test","sip contains \x22Hello, world\x5cx22\x22",""

并且生成的输出应该替换了转义序列,以便稍后在我的脚本中使用它们:

期望输出

sip contains "Hello, world\x22"

我的第一关是这样的:

当前解析器

filter_name=test
awk -v filter_name="$filter_name" 'BEGIN {FS="\",\""} ( == filter_name) {print }' "$config_file"

我的输出是这样的:

当前输出

sip contains \x22Hello, world\x5cx22\x22

我知道我可以通过管道传输到 sed 并匹配这两个确切的序列来处理这两个确切的转义序列,但是是否有通用的方法来替换所有转义序列?我构建的未来过滤器可能会使用更多的转义序列,而不仅仅是 " 和 ,我想处理未来的情况。

使用 gnu-awk,您可以使用 splitgensubstrtonum 函数执行此操作:

awk -F '","' -v filt='test' ' == filt {n = split(, subj, /\x[0-9a-fA-F]{2}/, seps); for (i=1; i<n; ++i) printf "%s%c", subj[i], strtonum("0" substr(seps[i], 2)); print subj[i]}' file

sip contains "Hello, world\x22"

更易读的形式:

awk -F '","' -v filt='test' '
 == filt {
   n = split(, subj, /\x[0-9a-fA-F]{2}/, seps)
   for (i=1; i<n; ++i)
      printf "%s%c", subj[i], strtonum("0" substr(seps[i], 2))
   print subj[i]
}' file

解释:

  • 使用 -F '","' 我们使用分隔符 ","
  • 拆分输入
  • == filt 我们根据 == "test" 条件过滤输入
  • 使用 /\x[0-9a-fA-F]{2}/ 作为正则表达式(匹配 2 位十六进制字符串)我们拆分 </code> 并将拆分标记保存到数组 <code>subj 并将匹配的分隔符保存到数组 seps
  • 我们使用 substr 删除第一个字符,即 \ 并添加 0
  • 我们使用 strtonum 将十六进制字符串转换为等效的 ascii 数字
  • printf中使用%c我们打印相应的ascii字符
  • 最后一个 for 循环使用 subjseps 数组元素将 连接回去

将 GNU awk 用于 FPAT、gensub()、strtonum() 和第三个参数以匹配 ():

$ cat tst.awk
BEGIN { FPAT="([^,]*)|(\"[^\"]*\")"; OFS="," }
 == ("\"" filter_name "\"") {
    gsub(/^"|"$/,"",)
    while ( match(,/(\x[0-9a-fA-F]{2})(.*)/,a) ) {
        printf "%s%c", substr(,1,RSTART-1), strtonum(gensub(/./,0,1,a[1]))
         = a[2]
    }
    print 
}

$ awk -v filter_name='test' -f tst.awk file
sip contains "Hello, world\x22"

以上假定您的转义序列总是 \x 后跟恰好 2 个十六进制数字。它隔离输入中的每个 \xHH 字符串,用 0 替换该字符串中的 \ 以便 strtonum() 可以将字符串转换为数字,然后使用 %cprintf 格式化字符串中将该数字转换为字符。

请注意,GNU awk 有一个调试器(请参阅 https://www.gnu.org/software/gawk/manual/gawk.html#Debugger),因此如果您不确定程序的任何部分是做什么的,您可以 运行 在调试器中进行调试(-D) 并追踪它,例如在下面我设置了一个断点来告诉 awk 在脚本的第 1 行停止 (b 1),然后开始 运行ning (r) 和步骤 (s ) 通过脚本在每一行打印 $3 (p ) 的值,这样我就可以看到它在 gsub():

之后是如何变化的
$ awk -D -v filter_name='test' -f tst.awk file
gawk> b 1
Breakpoint 1 set at file `tst.awk', line 1
gawk> r
Starting program:
Stopping in BEGIN ...
Breakpoint 1, main() at `tst.awk':1
1       BEGIN { FPAT="([^,]*)|(\"[^\"]*\")"; OFS="," }
gawk> p 
 = uninitialized field
gawk> s
Stopping in Rule ...
2        == "\"" filter_name "\"" {
gawk> p 
 = "\"sip contains \x22Hello, world\x5cx22\x22\""
gawk> s
3           gsub(/^"|"$/,"",)
gawk> p 
 = "\"sip contains \x22Hello, world\x5cx22\x22\""
gawk> s
4           while ( match(,/(\x[0-9a-fA-F]{2})(.*)/,a) ) {
gawk> p 
 = "sip contains \x22Hello, world\x5cx22\x22"