我尝试编写一个脚本,该脚本应该验证总详细记录是否等于Record_count
预告片记录,如果不匹配则抛出错误。
样本数据:
HDR9185 20210601094001202105311.11j
DTL226-42742-14 32.389185 NM30100000178103 D207935784ZAG Desjardins Trust CAD 5470.34 32.38A E 2.0500 5549.4420220215NESBITT BURNS INC A/C 226-42742-14 (5H94798) C 5014.0020170215N30100000178103 5H94798 ILPYA7SM71
DTL210-86993-11 21.979185 NM30100000187369 D207989578ZAG Desjardins Trust CAD 5036.97 21.97N A 2.0500 5117.8120220315NESBITT BURNS INC ITF A/C 210-86993-11 (5J10948) C 5015.0020170315N30100000187369 5J10948 ILQETLZDH1
TRL 02 93084.00
预告片记录02
是记录数。
我的代码:
if ! awk -F "|" ' /^HDR/ { h++; next; } /^TRL/ {t++; next} END { exit( (h != 1) || t != 1 || $NF != NR - 2 ); }' sample.txt
then
echo "file did not pass validation test"
exit 1
fi
echo "Validated successfully"
即使我的记录与预告片计数匹配或不匹配,这也会向我抛出“文件未通过验证测试”的标准输出。
答案1
您的代码似乎假设数据用作|
字段分隔符,但显然没有。看来您想断言确实存在一头记录 ( HDR...
) 和一尾记录 ( TRL
) 并且尾记录提到了正确的数字,即中间数据记录 ( ) 的数量DTL...
。
我假设该文件可能包含空行,并且应该忽略这些空行。
该awk
程序:
$1 ~ /^HDR/ { h++ }
$1 ~ /^DTL/ { d++ }
$1 == "TRL" { t++; ok = (d == $2) }
END { exit !(h == 1 && t == 1 && ok) }
对于每条HDR...
记录,h
都会递增。对于每条DTL...
记录,d
都会递增。当TRL
找到一条记录时,我们会递增t
并计算一个布尔值,ok
该值告诉我们数据行数是否正确。
如果我们END
恰好遇到了一个标头和尾部记录,并且该布尔ok
值为真的。
如果任何记录出现乱序,以下代码还会以非零退出状态退出(同时允许零数据记录):
BEGIN { ok = 1 }
$1 ~ /^HDR/ { h++; ok = (h == 1 && d == 0 && t == 0) }
$1 ~ /^DTL/ { d++; ok = (h == 1 && t == 0) }
$1 == "TRL" { t++; ok = (h == 1 && d == $2 && t == 1) }
!ok { exit }
END { exit !(h == 1 && t == 1 && ok) }
这可以保持布尔变量中数据的整体有效性ok
,并在该变量翻转到时以非零退出状态退出错误的(或者如果仍然存在,则退出状态为零真的整个代码的运行过程)。我们仍然需要确保在到达块时恰好看到一个头记录和尾记录END
,否则它将验证空文件是否正确。
要运行上述任一awk
程序,请将其放入文件中(此处validate.awk
)并使用
if awk -f validate.awk sample.txt; then
echo 'file ok'
else
echo 'file not validated'
fi
或者,在命令行上将整个程序作为单引号字符串给出:
if awk '$1 ~ /^HDR/ { h++ } $1 ~ /^DTL/ { d++ } $1 == "TRL" { t++; ok = (d == $2) } END { exit !(h == 1 && t == 1 && ok) }' sample.txt
then
echo 'file ok'
else
echo 'file not validated'
fi
寻址一条评论说该TRL
记录可能看起来像TRL0009 93084.00
where 0009
is the count of all types of record。
在这种情况下,第一个awk
程序可能看起来像
$1 ~ /^HDR/ { h++ }
$1 ~ /^DTL/ { d++ }
$1 ~ /^TRL/ { t++; ok = ( d == substr($0,4,4) - 2 ) }
END { exit !(h == 1 && t == 1 && ok) }
这里,substr($0,4,4)
用于挑选$0
(原始输入行)中从位置四开始、长度为四的字符串。我们从该数字中减去 2 以计算头记录和尾记录。
答案2
也许:
if awk -v RS='' '$1 == "TRL" {exit !($2 == (NR - 2))}' file; then
echo "success"
else
echo "invalid"
fi
awk 的RS = ""
意思是每条记录由空行分隔(又名“段落模式”)
我最初确实对该声明有解释
exit !($2 == (NR - 2))
但你的问题中有类似的代码,所以我认为你对此没意见。反正:
- 为了使预告片记录计数有效,整个文件必须精确地包含该计数加上标头和预告片。
- 整个文件中的记录数是awk NR变量
- 减去二,这应该是预告片中的计数。
- 与 C 类似,算术比较运算符返回 1 表示成功/0 表示失败
- shell 认为退出状态 0 表示成功,非零表示失败
==
所以我们否定操作符的返回码
我刚刚意识到我的代码不考虑出现的任何记录后预告片,这可能会使文件无效:试试这个
if awk -v RS='' '$1 == "TRL" {n = $2} END {exit !(n == NR - 2)}' file; then ...