【问题标题】:How can I output null-terminated strings in Awk?如何在 Awk 中输出以空字符结尾的字符串?
【发布时间】:2012-02-03 18:05:33
【问题描述】:

我正在编写一个可供其他人使用的 shell 脚本,并且可能会接收可疑字符串。它基于 awk,因此作为一项基本的弹性措施,我希望 awk 输出以空字符结尾的字符串 - 将从 awk 接收数据的命令因此可以避免包含空格或不常见的字符串的一定量的破坏-英文字符。

不幸的是,从基本的awk 文档中,我不知道如何告诉 awk 打印以 ASCII null 而不是换行符结尾的字符串。如何告诉 awk 我想要以 null 结尾的字符串?


可能使用的 awk 版本:

[user@server1]$ awk --version
awk version 20070501

[user@server2]$ awk -W version
mawk 1.3.3 Nov 1996, Copyright (C) Michael D. Brennan

[user@server3]$ awk -W version
GNU Awk 3.1.7

几乎是awk 的整个家族。如果我们必须整合一个版本,它可能是 GNU Awk,但欢迎所有版本的答案,因为我可能必须让它在所有这些 awk 上工作。哦,遗留脚本。

【问题讨论】:

  • 迄今为止我找到的最佳指南:sandrotosi.blogspot.com/2011/09/… - 但这还不是一个完整的答案,而且随机 blogspot 博客的 SEO 效果也比 SO 少,所以一个好的 SO 答案会很有用给更多人。
  • 凯文:想把它变成答案吗?
  • 对不起,使用\0 作为输入分隔符。我无法让 awk 将其用作输出分隔符。
  • 对,因为FSORS 不同。

标签: shell awk


【解决方案1】:

好的,我知道了。

awk '{printf "%s\0", $0}'

或者,使用ORS

awk -vORS=$'\0' //

【讨论】:

  • 当我将这些咒语的结果通过管道传输到 xargs -0 时,它不会在 awk 插入的 \0 上拆分(通过拆分其他内容进行测试)。 :(
  • @SeanM 第一个似乎不起作用,但第二个对我有用,你确定问题出在awk 吗? (尝试将输出保存到文件中)
  • 你可以通过管道检查 awk 的实际输出到od -cAn。我发现 gawk 会输出 NUL 字节,但 FreeBSD 上的 BusyBox awk 和 nawk 不会。 printf "%c","" 的 sandrotosi.blogspot.com 技术也不适用于这些实现。
  • 我不得不为-vORS 参数awk -vORS=$"\0" 使用双引号。这是在 gawk 4.0.1 中使用的。
  • -v 不受 BSD awk 支持,例如OSX中的那个。将\0 插入到字符串中都不起作用,而是将其视为字符串的结尾。
【解决方案2】:

有三种选择:

  1. 将 ORS 设置为 ASCII 零: 其他解决方案有awk -vORS=$'\0' 但是:
    $'\0' 是特定于某些 shell(bash、zsh)的构造。
    所以:这个命令 awk -vORS=$'\0' 在大多数旧的 shell 中都不起作用。

可以选择将其写为:awk 'BEGIN { ORS = "\0" } ; { print $0 }',但这不适用于大多数 awk 版本。

  1. 打印(printf)字符为\0awk '{printf( "%s\0", $0)}'

  2. 直接打印ASCII 0:awk '{ printf( "%s%c", $0, 0 )}'

使用此代码测试所有备选方案:

#!/bin/bash

test1(){   # '{printf( "%s%c",$0,0)}'|
    a='awk,mawk,original-awk,busybox awk'
    IFS=',' read -ra line <<<"$a"
    for i in "${line[@]}"; do
        printf "%14.12s %40s" "$i" "$1"
        echo -ne "a\nb\nc\n" |
        $i "$1"|
        od -cAn;
    done
}

#test1 '{print}'
test1 'BEGIN { ORS = "\0" } ; { print $0 }'
test1 '{ printf "%s\0", $0}'
test1 '{ printf( "%s%c", $0, 0 )}'

我们得到这个结果:

            awk      BEGIN { ORS = "\0" } ; { print $0 }   a  \0   b  \0   c  \0
           mawk      BEGIN { ORS = "\0" } ; { print $0 }   a   b   c
   original-awk      BEGIN { ORS = "\0" } ; { print $0 }   a   b   c
    busybox awk      BEGIN { ORS = "\0" } ; { print $0 }   a   b   c
            awk                     { printf "%s\0", $0}   a  \0   b  \0   c  \0
           mawk                     { printf "%s\0", $0}   a   b   c
   original-awk                     { printf "%s\0", $0}   a   b   c
    busybox awk                     { printf "%s\0", $0}   a   b   c
            awk               { printf( "%s%c", $0, 0 )}   a  \0   b  \0   c  \0
           mawk               { printf( "%s%c", $0, 0 )}   a  \0   b  \0   c  \0
   original-awk               { printf( "%s%c", $0, 0 )}   a  \0   b  \0   c  \0
    busybox awk               { printf( "%s%c", $0, 0 )}   a   b   c

如上所示,前两种解决方案仅适用于 GNU AWK。

最便携的是第三种解决方案:'{ printf( "%s%c", $0, 0 )}'

没有解决方案在“busybox awk”中正常工作。

用于此测试的版本是:

          awk> GNU Awk 4.0.1
         mawk> mawk 1.3.3 Nov 1996, Copyright (C) Michael D. Brennan
 original-awk> awk version 20110810
      busybox> BusyBox v1.20.2 (Debian 1:1.20.0-7) multi-call binary.

【讨论】:

  • 感谢您指定您使用的版本!启发这个问题的问题早已成为 Not Mine,但看到人们留下有用的、勤奋的答案,我的心很好。干得好。
  • 谢谢,%c 选项正是我想要的。不依赖当前shell的逃逸魔法就完美了。
【解决方案3】:

你也可以通过 tr 管道你的 awk 的输出:

awk '{...code...}' infile | tr '\n' '\0' > outfile

刚刚测试,它至少可以在 Linux 和 FreeBSD 上运行。

如果您不能使用换行符作为分隔符(例如,如果输出记录可以在内部包含换行符),只需使用一些其他保证不会出现在记录中的字符,例如代码为 1 的那个:

awk 'BEGIN { ORS="\001" } {...code...}' | tr '\001' '\0'

【讨论】:

  • 据我所知,这是最便携和最可靠的答案。 tr '\n' '\0' 甚至可以在busybox 中使用(与busybox 的awk 中使用空字符不同)。而不是使用\001(标题开头),我推荐\036(U+001e,信息分隔符二,又名记录分隔符,RS),因为信息分隔符是为此目的而制作的。 (#2/RS 映射到行(awk 的默认 ORS),而#1,单位分隔符,将类似于 awk 的 FS。)更多 en.wikipedia.org/wiki/Delimiter#ASCII_delimited_text
  • 由于 UNIX 路径可以包含除 \0 之外的任何字节,如果您使用其他任何内容,即使您之后将其替换为 \0,您也不会这样做:具有相同代码的任何内联字节也会被替换。
【解决方案4】:

我已经解决了从 awk 打印 ASCII 0 的问题。 我使用 UNIX 命令 printf "\000"

echo | awk -v s='printf "\000"' '{system(s);}'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-06
    • 1970-01-01
    • 1970-01-01
    • 2021-10-25
    • 2013-04-07
    相关资源
    最近更新 更多