Reputation: 89
I'm trying to count the number of entries in a set of log files. Some of these logs have lines that should not be counted (the number of these remains constant). The way I'd like to go about this is a Perl script that iterates over a hash, which maps log names to a one-liner that gets the number of entries for that particular log (I figured this would be easier to maintain than dozens of if-else statements)
Getting the number of lines is simple:
wc -l [logfile] | cut -f1 -d " "
The issue is when I need to subtract, say, 1 or 2 from this value. I tried the following:
expr( wc -l [logfile] | cut -f1 -d " " ) - 1
But this results in an error:
Badly placed ()'s.
: Command not found.
How do I perform arithmetic operations on the output of a shell command? Is there a better way to do this?
Upvotes: 0
Views: 1912
Reputation: 1650
The existing answers went in the direction of solving your issue in perl
, which you mentioned but your own experiments were in shell syntax.
You indicated tcsh
but expr
is Posix shell syntax.
Here is an example of a csh
script that counts the number of lines in a file whose name it is passed and then does arithmetic on the number of lines.
set lines=`wc -l < $1`
@ oneless = ($lines - 1)
echo "There are $lines in $1 and minus one makes $oneless"
Test:
csh count.csh count.csh
There are 3 lines in count.csh and minus one makes 2
Upvotes: 0
Reputation: 126742
It's a bit clunky to shell out to wc
and cut
just to count the number of lines in a file.
Your requirement isn't very clear, but this Perl code creates a hash that relates every log file in the current directory to the number of lines it contains. It works by reading each file into an array of lines, and then evaluating that array in scalar context to give the line count. I hope it's obvious how to subtract a constant delta from each line count.
use strict;
use warnings;
my %lines;
for my $logfile ( glob '*.log' ) {
my $num_lines = do {
open my $fh, '<', $logfile or die qq{Unable to open "$logfile" for input: $!};
my @lines = <$fh>;
};
$lines{$logfile} = $num_lines;
}
Update
After a comment from w.k
, I think this version may be rather nicer
use strict;
use warnings;
my %lines;
for my $logfile ( glob '*.log' ) {
open my $fh, '<', $logfile or die qq{Unable to open "$logfile" for input: $!};
1 while <$fh>;
$lines{$logfile} = $.;
}
Upvotes: 0
Reputation: 113934
To display one less than the number of lines with bash
or any bourne-like shell:
echo $(( $(wc -l <file) - 1 ))
To get the number of lines, you used:
wc -l logfile | cut -f1 -d " "
cut
is required here because wc
copies the file name to its output. To avoid that, and thus avoid the need for cut
, supply the input to wc
via stdin:
wc -l <logfile
In modern (POSIX) shells, arithmetic is done with $((...))
. Thus, we can substract one from the number of lines via:
$(( $(wc -l <file) - 1 ))
Upvotes: 1