#!/usr/bin/env perl use strict; use warnings; use File::Basename; =head1 NAME report2tsv - convert scanWordPressBackdoors' report into tab-separated values =head1 SYNOPSIS scanWordPressBackdoors.sh /path/to/clients | report2tsv > report.tsv =head1 DESCRIPTION Reads a scanWordPressBackdoors report on STDIN and writes TSV to STDOUT: the first output line is the report's "Scan root:" line, unchanged; every suspicious file thereafter becomes one tab-separated row of C, C, C, C. Section headers, the per-site "[suspicious files: N]" counts, blank lines, and trailing "skipped"/"Done." footers are dropped - they carry no per-file data. =cut my $site = ''; my ($pending_score, $pending_file, $pending_matches); sub flush_pending { return unless defined $pending_score; print join("\t", $site, $pending_score, basename($pending_file), $pending_file, $pending_matches // ''), "\n"; undef $pending_score; undef $pending_file; undef $pending_matches; } my $first_line = ; if (defined $first_line) { chomp $first_line; print "$first_line\n"; } # print Header line for TSV output print join("\t", qw(client/web score filename path matches)), "\n"; while (my $line = ) { chomp $line; next if $line eq ''; if ($line =~ /^(\S+)\s+\[suspicious files:\s*\d+\]\s*$/) { flush_pending(); $site = $1; next; } if ($line =~ /^\s*-\s*score=(\d+)\s+(.*\S)\s*$/) { flush_pending(); $pending_score = $1; $pending_file = $2; next; } if ($line =~ /^\s*matches:\s*(.*\S)\s*$/) { $pending_matches = $1; flush_pending(); next; } # Anything else (section headers, "No obvious suspicious sites...", # "(N file(s) skipped...)", "Done.") carries no per-file data - skip it. } flush_pending();