在 awk 中,如何将包含多个格式字符串的文件与 printf 一起使用?

2024-01-06

我有一个例子,我想使用文件的输入作为格式printf()在 awk 中。当我将其设置在代码中的字符串中时,我的格式有效,但当我从输入加载它时,它不起作用。

这是问题的一个小例子:

$ # putting the format in a variable works just fine:
$ echo "" | awk -vs="hello:\t%s\n\tfoo" '{printf(s "bar\n", "world");}'
hello:  world
        foobar
$ # But getting the format from an input file does not.
$ echo "hello:\t%s\n\tfoo" | awk '{s=$0; printf(s "bar\n", "world");}'
hello:\tworld\n\tfoobar
$ 

所以......格式替换有效(“%s"),但不是制表符和换行符等特殊字符。知道为什么会发生这种情况吗?有没有办法“做一些事情”来输入数据以使其可用作格式字符串?

更新#1:

作为进一步的示例,请考虑使用 bash heretext 进行以下操作:

[me@here ~]$ awk -vs="hello: %s\nworld: %s\n" '{printf(s, "foo", "bar");}' <<<""
hello: foo
world: bar
[me@here ~]$ awk '{s=$0; printf(s, "foo", "bar");}' <<<"hello: %s\nworld: %s\n"
hello: foo\nworld: bar\n[me@here ~]$

据我所知,多个不同的 awk 解释器都会发生同样的情况,并且我无法找到任何解释原因的文档。

更新#2:

我试图替换的代码目前看起来像这样,在 shell 中带有嵌套循环。目前,awk 是only被用于其printf,并且可以替换为基于 shell 的printf:

#!/bin/sh

while read -r fmtid fmt; do
  while read cid name addy; do
    awk -vfmt="$fmt" -vcid="$cid" -vname="$name" -vaddy="$addy" \
      'BEGIN{printf(fmt,cid,name,addy)}' > /path/$fmtid/$cid
  done < /path/to/sampledata
done < /path/to/fmtstrings

输入示例为:

## fmtstrings:
1 ID:%04d Name:%s\nAddress: %s\n\n
2 CustomerID:\t%-4d\t\tName: %s\n\t\t\t\tAddress: %s\n
3 Customer: %d / %s (%s)\n

## sampledata:
5 Companyname 123 Somewhere Street
12 Othercompany 234 Elsewhere

我的希望是我能够构造这样的东西,通过一次 awk 调用来完成整个事情,而不是在 shell 中使用嵌套循环:

awk '

  NR==FNR { fmts[$1]=$2; next; }

  {
    for(fmtid in fmts) {
      outputfile=sprintf("/path/%d/%d", fmtid, custid);
      printf(fmts[fmtid], $1, $2) > outputfile;
    }
  }

' /path/to/fmtstrings /path/to/sampledata

显然,这是行不通的,既因为这个问题的实际主题,也因为我还没有弄清楚如何优雅地使 awk 将 $2..$n 连接到单个变量中。 (但这是未来可能出现的问题的主题。)

FWIW,我正在使用内置的 FreeBSD 9.2,但如果可以找到解决方案,我愿意使用 gawk。


为什么这个例子如此冗长和复杂?这说明了这个问题:

$ echo "" | awk '{s="a\t%s"; printf s"\n","b"}'
a       b

$ echo "a\t%s" | awk '{s=$0; printf s"\n","b"}'
a\tb

在第一种情况下,字符串“a\t%s”是字符串文字,因此会被解释两次 - 一次是在 awk 读取脚本时,另一次是在执行脚本时,因此\t在第一次传递时展开,然后在执行时 awk 在格式化字符串中有一个文本制表符。

在第二种情况下,awk 在格式化字符串中仍然具有字符反斜杠和 t - 因此行为不同。

您需要一些东西来解释这些转义字符,一种方法是调用 shell 的 printf 并读取结果(根据 @EtanReiser 的出色观察进行更正,我在应该使用单引号的地方使用了双引号,在这里由 \047 实现,以避免 shell 扩展):

$ echo 'a\t%s' | awk '{"printf \047" $0 "\047 " "b" | getline s; print s}'
a       b

如果你不需要变量中的结果,你可以调用system().

如果您只是想扩展转义字符,那么您不需要提供%sshell 中的参数printf打电话,你只需要逃避所有%s(注意已经逃逸的%s).

你可以调用 awk 而不是 shellprintf如果你更喜欢。

请注意,这种方法虽然笨拙,但比调用eval这可能只是执行一个输入行,例如rm -rf /*.*!

在 Arnold Robbins(gawk 的创建者)和 Manuel Collado(另一位著名的 awk 专家)的帮助下,以下脚本将扩展单字符转义序列:

$ cat tst2.awk
function expandEscapes(old,     segs, segNr, escs, idx, new) {
    split(old,segs,/\\./,escs)
    for (segNr=1; segNr in segs; segNr++) {
        if ( idx = index( "abfnrtv", substr(escs[segNr],2,1) ) )
            escs[segNr] = substr("\a\b\f\n\r\t\v", idx, 1)
        new = new segs[segNr] escs[segNr]
    }
    return new
}

{
    s = expandEscapes($0)
    printf s, "foo", "bar"
}

.

$ awk -f tst2.awk <<<"hello: %s\nworld: %s\n"
hello: foo
world: bar

或者,这应该在功能上等效,但不是特定于 gawk 的:

function expandEscapes(tail,   head, esc, idx) {
    head = ""
    while ( match(tail, /\\./) ) {
        esc  = substr( tail, RSTART + 1, 1 )
        head = head substr( tail, 1, RSTART-1 )
        tail = substr( tail, RSTART + 2 )
        idx  = index( "abfnrtv", esc )
        if ( idx )
             esc = substr( "\a\b\f\n\r\t\v", idx, 1 )
        head = head esc
    }

    return (head tail)
} 

如果您愿意,可以将 split() RE 更改为

/\\(x[0-9a-fA-F]*|[0-7]{1,3}|.)/

以及之后的十六进制值\\:

c = sprintf("%c", strtonum("0x" rest_of_str))

对于八进制值:

c = sprintf("%c", strtonum("0" rest_of_str))
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 awk 中,如何将包含多个格式字符串的文件与 printf 一起使用? 的相关文章

随机推荐

  • Lodash 去抖动不起作用

    const debounce require lodash debounce gt console log testing 1000 leading true trailing false 上面的代码不起作用 https lodash co
  • 共享异常实例是否安全

    我们正在制作一个类似Excel 的系统 当我们打开文档并发现不支持的功能时 我们会抛出异常 我们只支持一小部分 Excel 函数 这种情况可能会经常发生 问题是 当有很多单元格包含不受支持的功能时 就会创建大量异常实例 创建这么多异常实例会
  • cygwin 中的 aws cli - 如何清理 Windows 和 cygwin 样式路径中的差异

    我怀疑这是我在正确设置路径变量方面的无能 但我不知所措 我已经在 cygwin 中使用 pip 安装了 aws cli pip install awscli 我有两个 python 环境 一个 windows anaconda 发行版 以及
  • github:没有拉取请求的代码审查?

    Using a 共享存储库模型 https help github com articles about collaborative development models 简而言之 我们希望能够审查代码更改 但是 我们根本不希望拉取请求阻碍
  • 跨环境导出和导入安全权限的最佳方法是什么?

    我们有大量的出版物 目前我们在多个环境 主要是 UAT 和 PROD 中手动应用 CMS 权限 这是很乏味的 而且经常容易出错 我们正在尝试跨多个环境导出和导入 CMS 权限 因此可以手动完成一次 然后使用某种工具移植到其他环境 环境 Tr
  • 如何在 Azure 函数中接收多部分表单数据?

    我想在 Azure Function 中接收包含图像和文本的多部分数据 我可以看到很多 C 和 Node 中的示例节点链接 https www builtwithcloud com multipart form data processin
  • 为什么 MutationObserver 代码不能在 Chrome 30 上运行?

    From http updates html5rocks com 2012 02 Detect DOM changes with Mutation Observers http updates html5rocks com 2012 02
  • 在 Android 浏览器中使用 HTML5 播放音频

    我想在以下位置播放音频Android浏览器 使用html5
  • 如何折叠 CSS 网格中未使用的行?

    因此 我在移动设备上有一个由三个段落组成的简单堆栈 我想在较大视口上的网格中设置样式 而不更改源顺序 第一部分可能有几行内容 也可能根本没有内容 在这种情况下 如何使第一行折叠以便第二行填充空间 IE 当顶部部分为空时 最后一个部分应出现在
  • 将数据插入3个相关表中

    如何将数据插入3个相关表 SQL Server 例如 我有表 Customer Address 将数据插入到 客户 和 地址 后 如何将 客户 和 地址 中的 ID 插入到 客户地址 中 连接表 Thanks Use 范围标识 http m
  • 在面板中绘制不同数据帧的同一列

    我从模拟中获得了数据 该数据为我提供了存储在 DataFrame 中的一些值 100 行 x 6 列 对于不同的起始值 我将数据保存在面板中 2 个数据框 x 100 行 x 6 列 现在我想比较两个模拟中名为 A 的列 名为 Sim1 和
  • 带有参数的 Emberjs 路由在某些情况下会失败

    在某些情况下 我遇到了路由 url 的问题 这是我的路由器 contacts Em Route extend route contacts index Em Route extend route connectOutlets functio
  • 使用 LINQ 比较两个数组

    例如 我有两个数组 string arrayOne One Two Three Three Three string arrayTwo One Two Three var result arrayOne Except arrayTwo fo
  • 自定义部分的 Web 配置转换

    我的 MVC 5 应用程序中有许多不同的 Web configs 用于不同的环境 例如测试 生产 我有适当的网络转换来更改不同环境的值 例如 我的 web config 文件中有以下应用程序设置
  • 使用 PHP/MySQL/JS 进行类似 facebook 聊天的后端服务器软件?

    我用 PHP 和 JavaScript 开发了一个类似 Facebook 的聊天工具 这是一个论坛软件的插件 目前我正在使用 短 轮询来接收新消息 但我想尝试使用更好的东西 例如套接字 对于这种聊天 每个网站都可用 私人聊天 群聊 您会推荐
  • 没有运气为 Python 3 pip 安装 pylint

    我有兴趣对我的 Python 3 代码运行检查器以指出可能的缺陷 py检查器 http pychecker sourceforge net 不适用于 Python 3 我尝试 pip install Pylint 但失败了 错误消息对我没有
  • Arduino 支持线程吗?

    我有几个任务需要用arduino来做 但其中一个需要很长时间 所以我想使用线程来同时运行它们 我有一个 Arduino Mega 更新 四年后 我终于可以在我的 arduino mega 上安装 FreeRTOS 这里有一个link htt
  • Python 2.7.3 _sqlite3 模块在传递标头/库后未构建[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我们有一个需要启动的 Django 项目 但无法为持久存储构建 sqlite sqlite3 dev 标头 库是not系统默认安装的我对此框没有 ro
  • 如何在适配器类中调用 getIntent()

    在 getView 方法中我想调用 getIntent 我怎样才能在不开始新活动的情况下实现这一目标 getView方法是这样的 public View getView final int position View convertView
  • 在 awk 中,如何将包含多个格式字符串的文件与 printf 一起使用?

    我有一个例子 我想使用文件的输入作为格式printf 在 awk 中 当我将其设置在代码中的字符串中时 我的格式有效 但当我从输入加载它时 它不起作用 这是问题的一个小例子 putting the format in a variable