awk脚本来检查文件是否存在并合并文件中的行
我正在使用sqlldr脚本将数据加载到Oracle表中。它生成3个文件,一个日志文件,坏数据文件和丢弃的记录文件。awk脚本来检查文件是否存在并合并文件中的行
我在网络上发现了一个漂亮的脚本,它解析这些文件并将日志文件中的错误与适当的记录关联起来。我不记得我找到的网站。我现在想在脚本中添加一个检查来检查这些文件是否存在,并且我正在尝试理解脚本,以便添加逻辑。
我还没有做awk之前。
这是脚本。请有人解释前4行是什么?
awk '
FNR==1 { FileNum++ }
FileNum==1 { Bad[FNR] = $0 ; next }
FileNum==2 { Dis[FNR] = $0 ; next }
/^Record [0-9]+: Rejected/ {
rec = Bad[++Rejected];
col = $NF;
getline;
sub(/^ORA-[^:]*:[[:space:]]*/, "");
print rec, "Error on column", col;
next;
}
/^Record [0-9]+: Discarded/ {
rec = Dis[++discarded];
sub(/.*Discarded - /, "")
print rec, $0;
next;
}
' file.bad file.discarded file.log
UPDATE ======
@Ed - 例如低于
添加文件的例子和预期输出
SQLLDR完成执行后,三个文件已被克隆, - 日志文件 - 错误的数据文件,并 - 丢弃记录文件
日志文件将具有控制文件,然后任何错误都记录
例如
Record 5: Discarded - failed all WHEN clauses
。 - 这一切都被丢弃的文件
- 以下2转到坏数据文件
Record 6: Rejected - Error on table SCH_USER.TEMP_RESULT.
ORA-00001: unique constraint (SCH_USER.PK_TEMP_RESULT) violated
Record 7: Rejected - Error on table SCH_USER.TEMP_RESULT.
ORA-00001: unique constraint (SCH_USER.PK_TEMP_RESULT) violated
**Log file**
Record 5: Discarded - failed all WHEN clauses
Record 6: Rejected - Error on table SCH_USER.TEMP_RESULT.
ORA-00001: unique constraint (SCH_USER.PK_TEMP_RESULT) violated
Record 7: Rejected - Error on table SCH_USER.TEMP_RESULT.
ORA-00001: unique constraint (SCH_USER.PK_TEMP_RESULT) violated
**Discarded file**
6296|0205|351004|666181|F.8.5|C|1|3|GP|
**Bad data file**
6296|0205|441201|666181|F.8.5|E|1|3|CS|
6296|0205|461210|666181|F.8.5|E|1|3|EM GW|
运行该脚本后,将输出重定向到一个文件时,输出看起来像这样
6296|0205|351004|666181|F.8.5|C|1|3|GP| failed all WHEN clauses.
6296|0205|441201|666181|F.8.5|E|1|3|CS| ******************Error on table SCH_USER.TEMP_RESULT. Actual Error : ORA-00001: unique constraint (SCH_USER.PK_TEMP_RESULT) violated
6296|0205|461210|666181|F.8.5|E|1|3|EM GW| ******************Error on table SCH_USER.TEMP_RESULT. Actual Error : ORA-00001: unique constraint (SCH_USER.PK_TEMP_RESULT) violated
在上面的场景中,有可能是坏数据文件或丢弃文件或两者都不存在(这是个好消息,使用sqlldr时没有错误)。我希望能够使用脚本优雅地处理这两个场景。
我希望这是可能的。你会让我知道吗,我该如何实现它?
FNR==1 { FileNum++ }
FNR是文件记录号,它的每个文件后重置,使用这种条件脚本知道是什么文件,它的工作对
FileNum==1 { Bad[FNR] = $0 ; next }
如果脚本处理的第一个文件中的线($ 0)添加到使用记录号索引的数组(这里是行),next
跳过脚本的其余部分以处理下一条记录。
FileNum==2 {
相同现在第二文件
/^Record [0-9]+: Rejected/
现在脚本处理所述第三文件,模式匹配每行开始“记录”,空间,一个或多个数字,“:被拒绝”。对于匹配的行,请执行块中的操作。
UPDATE awk
通过记录操作文件记录(此处默认记录是行)。使用这种方法它只会查找非空文件,空文件将被跳过。在新文件中,文件记录号FNR
将重置为1.检查此值将指示是否完成一个文件并启动下一个(非空)文件。 FileNum是用户定义的变量。该脚本是在考虑输入参数的情况下编写的。前两个文件将存储在由行号索引的数组中,并在第三个文件上作为参考进行操作。它不知道文件是否存在,如果文件不存在就会失败。在调用awk之前将其保留为shell可能会更好。
貌似OP可能已经离开大楼,但对其他任何人想知道如何明确处理不存在或无法打开其他原因的文件,这里的做法:
$ cat ../tst.awk
BEGIN {
badFiles = rmvBadFiles()
if (badFiles != "") {
printf "ERROR: cannot read from file(s):\n%s\n", badFiles | "cat>&2"
# Add "exit 1" if you want to exit instead of continuing
}
}
{ print FILENAME, $0 }
function rmvBadFiles( _argind,_file,_line,_badFiles) {
for (_argind=1; _argind < ARGC ; _argind++) {
_file = ARGV[_argind]
if (_file !~ /^([[:alnum:]_]+=.*|-?)$/) {
if ((getline _line < _file) < 0) {
_badFiles = (_badFiles == "" ? "" : _badFiles "\n") _file
ARGV[_argind] = ""
}
close(_file)
}
}
return _badFiles
}
例如:
$ ls
file1 file2
$ cat file1
a
$ cat file2
b
$ awk -f ../tst.awk file1 garbage file2
file1 a
file2 b
ERROR: cannot read from file(s):
garbage
,而不是默认的行为:
$ awk '{print FILENAME, $0}' file1 garbage file2
file1 a
awk: cmd. line:1: fatal: cannot open file `garbage' for reading (No such file or directory)
谢谢。仍试图了解第一行的功能。那么,它是否通过比较我们是否在第一条记录来检查它是否是新文件,如果我们是那么它会增加FileNum变量?它如何确定文件的总数量。它是否发生在隐式循环中? FileNum也是一个awk特定变量,还是用户定义的?所以,如果我想检查文件是否存在,那么在检查FileNum == 1或2之后,我应该在大括号内进行检查吗?对于大量问题抱歉,但在网上搜索时找不到这种类型的详细信息。 – adbdkb
@adbdkb所有这些细节和更多内容都在Arnold Robbins出版的第4版Effective Awk Programming中进行了解释。 –
再次感谢@karakfa - 我已经对它如何执行程序有了很高的理解,并且您的解释将帮助我破译代码。我想检查脚本中是否存在文件的原因是,在sqlldr按计划运行后,我将每天使用它。因此,有时候坏的和dsc文件中的一个或两个文件不存在,所以我想检查并执行适当的处理。那是可行的吗?和一个有效的想法?或者你还是建议在调用awk之前在外面做这件事?这不需要我有多个awk脚本? – adbdkb