awk中如何记录之前的操作结果?

awk中如何记录之前的操作结果?

我有一个包含以下格式数据的文件。有 3 行需要保持在一起,并且它们具有可预测的模式:

dn: uid=N-NAME-02, ou=data01, dc=data02, dc=data03
uidNumber: 3423
sambaSID: S-1-1-11-1111111-111111111-11111111-12342
<blank line>
dn: uid=N-NAME-03, ou=data01, dc=data02, dc=data03
uidNumber: 3245
sambaSID: S-1-1-11-1111111-111111111-11111111-32212

我需要根据 3 组中的第二串数据进行一些数学计算,然后将计算结果放入该组的第三串中:

dn: uid=NAME02, ou=data01, dc=data02, dc=data03
uidNumber: (3423 + 2 * 100)
sambaSID: S-1-1-11-1111111-111111111-11111111-342500
<blank line>
dn: uid=NAME03, ou=data01, dc=data02, dc=data03
uidNumber: (3245 + 2 * 100)
sambaSID: S-1-1-11-1111111-111111111-11111111-324700

我想我可以再次使用 AWK 来实现此目的,因为 AWK 可以进行数学计算并正确放置结果值。我自己得到了数学部分并将其存储在变量中

variable1=`awk -F ': ' '/uidNumber:/ { new = $2 * 2 + 1000; print new }' infile`

然后我可以在同一文件的另一个命令中使用这个变量来进行替换

awk -F '-' -v variable2=$variable1 '/pattern of string 3 / { print $1"-"$2"-"$3"-"$4"-"$5"-"$6"-"$7"-"variable2 }'

我应该提到的是,字符串 3 数据是一个用破折号“-”分隔的长字符串。最后一个破折号之后是需要放置计算值的位置。

这一切都有效,但有一个主要缺陷......它仅在文件中有一条记录时才有效。有人可以给我一个关于完成此任务的方法的提示吗?

答案1

您可以match()在以下位置使用该函数awk

$ cat file
somedata45
somedata47
somedata67

somedata53
somedata23
somedata12

awk '
BEGIN { RS = ""; OFS = "\n"; ORS = "\n\n" }
match($2, /[0-9]+/) { value = (substr($2, RSTART, RLENGTH) + 5) * 100 }
match($3, /[0-9]+/) { $3 = substr($2, 1, RSTART - 1) value }1' file
somedata45
somedata47
somedata5200

somedata53
somedata23
somedata2800

我们将记录分隔符设置为空,有效地启用段落模式(由空行分隔)。每个段落中的第二行成为我们的$2,第三行成为 $3 等等。我们将输出字段分隔符设置为换行符。由于段落模式,我们还将输出记录分隔符设置为两个换行符。输出将在最后给你一个额外的换行符。

我们使用该match()函数来识别数字的开头。当找到匹配时,该函数会为我们填充两个变量,RSTARTRLENGTH指示匹配何时开始以及持续多长时间。我们使用这些变量进行计算并将结果存储在名为 的变量中value。我们使用该substr函数来定位数字。

我们重复相同的操作$3,这次我们使用substr函数打印到数字开始的位置,并将数字部分替换为包含上一行计算值的变量。

请参考字符串函数请参阅用户指南了解更多详细信息。


根据真实数据更新:

您的真实数据实际上使事情变得简单得多。

awk '
/^uidNumber/ { value = $NF } 
 /^sambaSID/ { 
    n = split ($NF, tmp, /-/)
    tmp[n] = ((value + 2)* 100)
    for (i=1; i<=n; i++) { nf = (nf ? nf "-" tmp[i] : tmp[i]) }
    $NF = nf
    nf = ""
}1' file
dn: uid=NAME02, ou=data01, dc=data02, dc=data03
uidNumber: 3423
sambaSID: S-1-1-11-1111111-111111111-11111111-342500

dn: uid=NAME03, ou=data01, dc=data02, dc=data03
uidNumber: 3245
sambaSID: S-1-1-11-1111111-111111111-11111111-324700

您查找包含uidNumber最后一个字段的行并捕获它。当您看到一条线时,sambaSID您将拆分最后一个字段-并将最后一个元素修改为新的计算值。然后,您使用 afor loop重新组合您的最后一个字段。

答案2

我在 awk 脚本中执行此类操作的方法是保留一些变量来计算行数。您可以在单个脚本中完成此操作。

/^[ \t]*$/ { lineCnt = 0; continue } # this matches blank lines and resets the count
{ lineCnt++ }
lineCnt == 2 { ... strip off your numeric ... }
lineCnt == 3 { ... do whatever you need to with the math ... }

您可以通过在第 2 行和第 3 行的块末尾添加“继续”语句来稍微提高效率,因为您知道您已经完成了。

答案3

听起来您只是在问如何awk使用另一个中的变量值来组合多个模式动作表达式 - 这非常简单,例如

awk '/pattern2/ { calculate and assign var }; /pattern3/ {do something with var}'

在这种情况下并不是;绝对必要的,但有助于理解。在 awk 脚本(而不是单行脚本)中,您可能会用换行符分隔表达式。

例如,如果file

pattern1
pattern2 3 5
pattern3

然后

$ awk '/pattern2/ {var = $2+$3}; /pattern3/ {print; print var}' file
pattern3
8

另外,您可能希望看一下 awk 的内置函数OFS(输出字段分隔符)变量,它可以让您更轻松地格式化输出,例如给定

pattern1
pattern2-3-5
pattern3-4-6

然后

$ awk -F- '/pattern2/ {var = $2+$3}; /pattern3/ {OFS="-"; print $1,$2,$3,var}' file
pattern3-4-6-8

相关内容