3

I'd like to run a find command and then count the lines of the output as well as give out the output of the result. My straight-forward approach was this:

output=$(find ...)
lines=$(echo "$output" | wc -l)
echo "$output"

But unfortunately using echo to pipe this into wc adds a newline, so even if the find did not find anything (zero lines of output), that wc is giving out 1 (for the newline which the echo appended.

I changed the echo to a printf to prevent appending the newline to the output but then also a one-line output of find like var/ was without a newline, and hence the wc gave out 0.

The problem is in the capturing of the output ($(...)). It strips trailing newlines which in my case are relevant.

Can this be prevented somehow?

Is there a completely different approach on my original task?

Alfe
  • 56,346
  • 20
  • 107
  • 159
  • Related: [How to avoid bash command substitution to remove the newline character?](http://stackoverflow.com/questions/15184358/how-to-avoid-bash-command-substitution-to-remove-the-newline-character) – user000001 Apr 25 '14 at 13:57

3 Answers3

5

A simple workaround that would occur to mind would be to check if the string is empty:

[ -z "$output" ] && count=0 || count=$(wc -l <<< "$output")

Now count would be 0 if find didn't produce any output else it would contain the number of lines in the output.

devnull
  • 118,548
  • 33
  • 236
  • 227
3

Counting new lines after storing find's output in a variable is always going to be problematic in case your file names contain spaces or new lines.

I would suggest using find like this (to count all *.txt files and print them)

output=
c=0

while read -d ''; do 
    ((c++))
    output+="$REPLY"$'\n'
done < <(find . -name "*.txt" -print0)

echo "c=$c"
echo "output=$output"

PS: This will also take care of new lines/spaces in file names.

anubhava
  • 761,203
  • 64
  • 569
  • 643
  • Nice solution for the hard-ass case (when I have no idea what kind of input I'm expecting). In my case I know pretty much what the output will look like. There will be no spaces or newlines in the file names, that's sth I can rely on. So I'd rather not complicate my code with a solution like yours. But reading the output line by line to count it sounds like a good idea. I'll consider that. – Alfe Apr 25 '14 at 14:27
2

I'm now using a workaround by appending a fake line to the output; this way I can rely on the fact that one line will always be present, and this way the empty line is easily distinguishable from the one-line:

r=$(find var/ -name var -printf "%p\n"; echo '==')
# appending additional line to be able to distinguish 0 from 1 found file
case "$(echo "$r" | wc -l)" in
  1)  # means 0 found files
    ...
  2)  # means 1 found file
    ...
  *)  # means more found files
    ...
esac
Alfe
  • 56,346
  • 20
  • 107
  • 159
  • And what about your actual output? – anubhava Apr 25 '14 at 14:44
  • I guess you want to know how I can live with the additional `==` below the output. Actually, I can live with that, yes ;-) And in the case where it does not suit me fine, I strip that off. – Alfe Apr 25 '14 at 15:08