我有一个包含以下格式数据的文件。有 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()
函数来识别数字的开头。当找到匹配时,该函数会为我们填充两个变量,RSTART
并RLENGTH
指示匹配何时开始以及持续多长时间。我们使用这些变量进行计算并将结果存储在名为 的变量中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