我正在使用sqlldr脚本将数据加载到Oracle表中。它生成3个文件,一个日志文件,坏数据文件和丢弃的记录文件。
我在网上找到了一个漂亮的脚本来解析这些文件并将日志文件中的错误与适当的记录相关联。我不记得我发现它的网站了。我现在想在脚本中添加一个检查来检查这些文件是否存在,为此我试图理解脚本,以便我可以添加逻辑。
我之前没有做过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
更新 的 ==
@Ed - 以下示例
添加文件和预期输出的示例
sqlldr完成执行后,会创建三个文件, - 日志文件 - 错误的数据文件和 - 废弃的记录文件
日志文件将包含控制文件,然后记录任何错误
e.g。
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时没有错误)。我希望能够使用脚本优雅地处理这两种情况。
我希望这是可能的。你能告诉我,我怎么能实现它?
答案 0 :(得分:1)
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可能更好。
答案 1 :(得分:0)
看起来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)