Why does `echo $(find) | wc -l` not count the number of files correctly?

Viewed 188

Thats my function

function getFile(){
    echo $(find . -type f -regextype egrep -regex ${REGEX:-'.*\.(jpe?g|JPE?g)$'})
}

when i try to get that getFile return in my other funtion

function resize(){
    (( i=1 ))
    local k=`getFile | wc -l`
    echo $k
}

i don't have the same result if I do

function resize(){
    (( i=1 ))
    local k=`find . -type f -regextype egrep -regex ${REGEX:-'.*\.(jpe?g|JPE?g)$'} | wc -l`
    echo $k
}
2 Answers

The issue is in the getFile function. What you do there is to find the names of the jpeg (or whatever) files and then echo those. What it does is to print all of those in a single line. For instance, here's what I've got

./photo_2019-07-18_22-20-451.jpg ./photo_2019-07-18_22-20-45.jpg

Then you try to count those with wc -l which basically counts the number of lines in the output, thus it always gets 1.

On the other hand in the 2nd function, you don't echo the results that it is not a single line anymore, giving the right answer.

Simply remove the echo from getFile() and it will work

function getFile() {
    find . -type f -regextype egrep -regex ${REGEX:-'.*\.(jpe?g|JPE?g)$'};
}

it outputs

$ getFile

./photo_2019-07-18_22-20-451.jpg
./photo_2019-07-18_22-20-45.jpg

and finally

function resize(){
    (( i=1 ))
    local k=`getFile | wc -l`
    echo $k
}
$ resize
2

Counting lines of output from find is fragile, in that conceivably a filename could contain a newline. Since you don't appear to be constrained by POSIX compatibility, I would use something like

find . -type f -regextype egrep -regex "${REGEX:-.*\.(jpe?g|JPE?g)$}" -printf '.' | wc -c

to get the count. (No matter what the file's name is, find simply outputs a single character for wc to count.)

If you still need getFile to produce actual file names on occasion (with the caveat that a single output line may not be a complete file name), you can parameterize the function, for example:

getFile () {
  find_opts=(. -type f -regextype egrep -regex ${REGEX:-'.*\.(jpe?g|JPE?g)$'})
  count=
  for arg; do
    case $arg in
      -c) find_opts+=(-printf '.'); count=1 ;;
    esac
  done

  find "${find_opts[@]}" | if [ -z "$count" ]; then cat; else wc -c; fi
}

Then you can run

$ getfile
foo.jpg
bar.jpg

or

$ getfile -c
2
Related