在 suse linux 中,为了每小时分割慢查询日志,我使用下面的脚本。
如何解决该错误?
#!/bin/bash
# split mysql slow query log by hour
usage() {
cat <<EOF
Usage: $0 [options]
[REQUIRED]
-l
EOF
exit 1
}
while getopts "l:" opt; do
case $opt in
l) slowlog="$OPTARG" ;;
esac
done
[ -z "$slowlog" ] && usage
awk '{
if ($0~/^# Time*/) {
split($4, h, ":");
hour=h[1];
minute=h[2];
splitfile="mysql-slow.log-split-"substr($0, 9, 6)"-"hour".txt";
print $0 >> splitfile
} else {
print $0 >> splitfile
}
}' "$slowlog"
但在执行过程中出现以下错误:
mysql@eudc-mysql-lx03:/mysql-work/chandra> sh -x test_slow.sh -l eudc-mysql-lx03-slow.log
+ getopts l: opt
+ case $opt in
+ slowlog=eudc-mysql-lx03-slow.log
+ getopts l: opt
+ '[' -z eudc-mysql-lx03-slow.log ']'
+ awk '{
if ($0~/^# Time*/) {
split($4, h, ":");
hour=h[1];
minute=h[2];
splitfile="mysql-slow.log-split-"substr($0, 9, 6)"-"hour".txt";
print $0 >> splitfile
} else {
print $0 >> splitfile
}
}' eudc-mysql-lx03-slow.log
awk: cmd. line:8: (FILENAME=eudc-mysql-lx03-slow.log FNR=1) fatal: expression for `>>' redirection has null string value
答案1
您的问题是您else
在执行语句之前分支到该 if
语句,因此您在赋值之前使用变量splitline
,如注释中所述。在我看来,您在这里使用 awk 的唯一原因是提取日期并在每次小时或日期增加时重定向到不同的文件。仅当您保证日志的第一行始终是时间戳时,您的代码才有效,但事实似乎并非如此。您需要在遇到的第一个时间戳开始记录,为此我建议您对awk
代码片段进行简单的调整:
awk 'BEGIN{ date_found=0 }
/^# Time/ { date_found=1 }
date_found == 0 { continue }
date_found == 1 {
split($4, h, ":");
hour=h[1];
date=$3
splitfile="mysql-slow.log-split-"date"-"hour".txt";
date_found=2
}
{print $0 >> splitfile}' "$slowlog"
此方法的缺点:您不会存储大日志文件的第一个时间戳之前的日志内容!如果要存储第一个分割文件中第一个时间戳之前的行,则必须在运行主 awk 调用之前提取日期。它变得有点复杂,但你可以这样做:
first_date=$(awk '/^# Time/{print $3" "$4; exit}' "$slowlog")
awk -v init_date="$first_date" '
BEGIN{
split(init_date, a, " ")
date=a[1]
split(a[2], b, ":")
hour=b[1]
}
/^# Time/ {
split($4, h, ":");
hour=h[1];
date=$3
}
{
splitfile="mysql-slow.log-split-"date"-"hour".txt";
print $0 >> splitfile
}' "$slowlog"
任一解决方案都应适合您在问题中表达的需求。如果需要,请随时询问有关代码的问题。