首先,正常的 awk 代码假定逐行处理。事实上,如果没有额外的命令行选项,awk 会删除所有"\n"。因此,您尝试用 "; " 替换 "\n " 没有多大意义,因为您的代码永远不会看到“\n”。
要将多行合并为一行,您可以使用printf 而不是print:
/^[AC]\w/ {
printf "\n%s",$0
next
}
/^\s/ {
printf " %s",$0
next
}
上面的代码说,当遇到以A 或C 开头的行后跟一个单词字符(例如U 或1 或i)然后打印一个换行符后跟该行.当它遇到以空格字符(空格或制表符)开头的行时,打印没有换行符的行。
当然,这有一些小问题。例如,它在输出的开头打印一个换行符,最后没有换行符。而且它也不会去除以空格开头的行的前导空格。但我们暂时先把它留在这里。
这回答了您的第一步问题。
但这不是你想要的。您想要的是规范化 C1 值。所以首先让我们编写忽略除C1 值之外的所有内容的代码:
/^C1/ {print}
好的,现在我们需要处理所有属于C1 的选项卡行,所以我们需要稍微修改一下代码:
BEGIN {c1_found=0}
/^C1/ {
c1_found=1
print
next
}
/^\s/ {
if (c1_found == 1) {
print "C1 " $0
}
next
}
{
c1_found = 0
}
所以。我们创建一个变量c1_found 来标记我们在C1 块中。我们在 BEGIN 块中将其初始化为 0,并在遇到 C1 块时将其设置为 1。现在,每当我们看到以空格开头的行时,我们会检查我们是否在 C1 块中,并通过在其前面附加 "C1 " 来打印该行。
现在我们要处理标准化。这是困难的一点。让我们为此编写一个函数,因为它将在两个地方调用:
function normalize (c1_line) {
split(c1_line,a,"[[]]")
c1 = a[1]
names = a[2]
location = a[3]
split(names,b,";")
for (nam in b) {
print c1 b[nam] location
}
}
此函数首先将其输入拆分为[ 或],这会将行分成三个组成部分。然后它用; 分割第二部分。最后,它遍历名称并为每个名称打印一行。
现在让我们将其包含到我们的代码中:
function normalize (c1_line) {
split(c1_line,a,"[[]]")
c1 = a[1]
names = a[2]
location = a[3]
split(names,b,";")
for (nam in b) {
print c1 b[nam] location
}
}
BEGIN {c1_found=0}
/^C1/ {
c1_found=1
normalize($0)
next
}
/^\s/ {
if (c1_found == 1) {
normalize("C1 " $0)
}
next
}
{
c1_found = 0
}
上面的代码生成file1。现在,要生成 file2,最简单的方法是编写另一个仅打印国家/地区名称的脚本,然后通过sort 和uniq(或sort -u,如果您的排序可以做到这一点)进行管道传输。但是,如果您坚持在 awk 中执行,则可以(实际上它非常简单易读)。首先,我们使用关联数组来跟踪出现的所有国家/地区:
function normalize (c1_line) {
split(c1_line,a,"[[]]")
c1 = a[1]
names = a[2]
location = a[3]
split(names,b,";")
for (nam in b) {
print c1 b[nam] location
}
countries[$NF] = 1
}
然后我们将国家数组打印到一个文件中:
END {
for (c in countries) {
print c >> file2.txt
}
}
我将由您来组装完整的程序。但是正如您所看到的,与 C 或 perl 或汇编的 bash 或 pascal 相比,在 awk 中编程是完全不同的。它更像是在正则表达式中编程——因为 awk 有一个内置循环,当找到匹配项时会不断扫描输入并执行代码。
所以,作为一个例子,下面的程序:
BEGIN {print "starting"}
/^mango/ {print "ha"}
/^monkey/ {print $0}
END {print "done"}
完全等同于:
/^monkey/ {print $0}
END {print "done"}
BEGIN {print "starting"}
/^mango/ {print "ha"}
当匹配是彼此的子字符串时,存在细微差别。例如,当您想与/^HELLO/ 分开触发/^HEL/ 时。但一般执行不会自上而下线性读取。
另外,请注意 awk 只有全局变量。所以使用好的变量名来避免覆盖其他地方的一些其他变量。