Obtenha o erro awk “o redirecionamento tem valor de cadeia nula” ao dividir o arquivo

0

No suse linux para log de consultas lentas para dividir por hora, estou usando o script abaixo.
Como resolver o erro?

#!/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"

Mas durante a execução, ficando abaixo do erro:

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
    
por chandrapal panwar 29.03.2017 / 10:17

1 resposta

1

Seu problema é que você está ramificando para a instrução else antes de passar pela instrução if , portanto, você está usando a variável splitline antes da atribuição, como indicado nos comentários. Do jeito que eu vejo, a única razão pela qual você está usando o awk aqui é extrair a data e redirecionar para um arquivo diferente sempre que a hora ou a data forem incrementadas. Seu código só funcionaria se você tiver certeza de que a primeira linha do seu log é sempre um timestamp, mas parece que não é o caso. Você precisa começar a fazer o registro no primeiro registro de data e hora que encontrar. Para isso, proponho a você este simples ajuste no seu awk snippet:

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"

Desvantagem para este método: você não armazenará o conteúdo do log antes do primeiro timestamp do grande arquivo de log! Se você deseja armazenar as linhas antes do primeiro registro de data e hora no primeiro arquivo dividido, é necessário extrair a data antes de executar a chamada principal do awk. É um pouco mais complicado, mas você pode fazer isso:

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"

Ambas as soluções devem atender às necessidades expressas na pergunta. Não hesite em fazer perguntas sobre o código, se precisar.

    
por 04.04.2017 / 11:59