【发布时间】:2014-07-04 13:59:58
【问题描述】:
我有一个案例,我想使用来自文件的输入作为 awk 中printf() 的格式。当我在代码中的字符串中设置它时,我的格式有效,但当我从输入加载它时它不起作用。
这是问题的一个小例子:
$ # 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 仅用于其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。
【问题讨论】:
-
在激发问题的更大背景下,您是否将有多个输入行表示多个格式字符串(以便
printf将被多次调用,使用相同的数据但不同的格式字符串),还是您打算在整个awk程序中使用单个格式字符串(恰好是从文件中读取的)?为第一个场景设计一个合理的用途有点困难,但测试不同的格式选项可能是一个有效的用例。这很重要,因为评估一次可以通过多种方式完成;将多个输入分别评估为格式字符串更加困难。 -
@JonathanLeffler - 添加了更新#2,它更好地展示了我目前正在做什么以及我实际上希望看到的结果。找到足够多的例子来证明问题,同时保留足够的细节以免无用地加重问题的负担,这是一种平衡行为。
-
@Graham 我刚刚更新了我的答案,以包含一种相当简洁的方法来在单个 awk 命令中扩展转义字符。