1

I'm running a bash script to output logs under a log directory. Initially I want to know how many logs are generated, simply do the following:

ls logs | wc -l

And as the bash script is running in real time, I can further use:

watch -n 5 'ls logs | wc -l'

to display the number of log files concurrently.

But I also know the total number of log files that should be generated by checking how many lines under a file called file.txt by:

cat file.txt | wc -l

Now I want to display how many more logs need to be generated by substracting the two numbers, I searched, there are several ways to do math in shell, e.g. using expr or use double brackets. For example, assuming my total number of lines in file.txt are 1000. If I hard code this into the command, the final command would be like

`watch -n 5 'ls logs | wc -l | xargs expr 1000 - '

But I want to substitute 1000 with the result coming from cat file.txt | wc -l command. I tried the following but not working. I'm not sure if xargs can accept two arguments from 2 commands, or this is not how we use it here.

watch -n 5 'ls logs | wc -l | xargs expr "cat file.txt | wc -l" + '

(Note: what if I only want to count number of lines in file.txt that not begin with a # letter and not an empty line? How do I do that here?) Much appreciated.

1

I'm not sure if xargs can accept two arguments from 2 commands.

It can run a command with multiple arguments spread across multiple lines from input. For example, this will tell xargs to run expr with three arguments taken from input (which are, in order, the number of logs, -, and the number of lines in file.txt):

(ls logs | wc -l; printf "%s\n" -; wc -l < file.txt) | xargs -n 3 expr

It might be more idiomatic to use command substitution here:

expr "$(ls logs | wc -l)" - "$(wc -l < file.txt)"

[W]hat if I only want to count number of lines in file.txt that not begin with a # letter and not an empty line?

Count with grep:

grep -c -v -e '^#' -e '^$' file.txt
  • -c to count matching lines
  • -v to invert the match, so lines not matching the following are selected
  • -e '^# to match lines beginning (^) with a #
  • -e '^$ to match lines which end ($) immediately after they begin (^),, i.e., they are empty.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.