indication of find activity - bash script

Hi All,

I wanted to show on stdout that a file was found right after it happens due to indicate the activity of long search. Further more I want to store the result of the find in a file.

I have tried this:

echo -n "Searching"
find . -name Makefile -type f -print -exec echo -n "." \; > testPaths.log

Unfortunately dots are written to the file.
How could I separate output of -exec and result of find? or How could I indicate the find activity?

What about:

echo -n "Searching"
find . -name Makefile -type f -print -exec echo -n "." | tee -a testPaths.log

?

Or:

find . -name Makefile -type f 2> /dev/null | while read FILE; do printf "."; echo $FILE > testPaths.log; done
find . -name Makefile -type f -print -exec echo -n "." | tee -a testPaths.log

prints dot and path to both file and stdout due to piping (dot is printed right after a file is found)

while

find . -name Makefile -type f 2> /dev/null | while read FILE; do printf "."; echo $FILE > testPaths.log; done

prints the right characters to right places, but the printing of dot is execute just after the find finishes its work on the whole directory set.

Any other idea?

(at this point the piping mechanism is not clear for me: why tee is executed after each file found and why not executed while (just at the end)? Maybe this is the behaviour of while (like xargs echo)?)

I don't know if it works but I think it should work ^^'

find . -name Makefile -type f -print -exec tee -a testPaths.log | echo -n "."

What it is supposed to do:
first writes the found file to testPaths.log and then echo a dot, not the other way around
Sorry for explaining so bad ^^'
btw @scottn: if you take a look at find's man page:

maybe thats why it doesn't print the dot directly to stdout? Sorry I could also be terribly wrong about it ^^'

Why would it do that?

Perhaps it just runs too quickly for you to see.

Try putting a sleep (or usleep) in to test.

---------- Post updated at 03:02 PM ---------- Previous update was at 02:52 PM ----------

Hi.

I didn't use -exec.

The dots print perfectly fine, just, as I said too quickly. But when it finds a file, it prints a dot.

upps didn't see you didn't use it :o sry^^'

@al0x:

It just writes a dot to stdout and done. Maybe tee has no input.

@scottn:

I have tested it on a large folder set. I think that data is collected till end of find, then it is pushed to pipe on by one. In case of "| while" I see that the full time of search elapses and then everything is printed out in a sec.

I would really like to help more but for some reason my ubuntu-terminal rejects the command because "-exec needs arguments" :s
For the meantime:
I don't know if this will work but it's worth trying:

find . -name Makefile -type f -print -exec > testPaths.log | echo -n "."

I think " \;" is missing from end of -exec

:smiley: thanks ^^

maybe the fact that you can use multiple -exec commands for find can help you?
I don't have the time to try it right now sorry (a friend told me) ^^'

Another approach where we can do whatever we like each time we find a file.
Also improved order of parameters on the "find" line which should speed it up.

>testPaths.log
echo -n "Searching "
#
find . -type f -name Makefile -print|while read filename
do
        # Output filename to file
        echo "${filename}" >> testPaths.log
        # Output dot to screen with no linefeed
        echo -n "."
done
# Output a linefeed 
echo ""
echo "Finished"

Correct me if I am not right, but it seems that "whatever we like" is executed for each file just after find is finished its job in case of

find . -type f -name Makefile -print | while read filename
do
   ...
done

The construct is dynamic. The find command passes each matching filename to the while loop as it finds it. The while loop ends when find ends.

It is one of the best ways to process open-ended lists in Shell and has the advantage of preserving spaces in filenames.

Though not relevant to your post if you want to find just one file you can exit the loop as soon as you find the file.

The solution for one by one feed of while loop is

# Open the file
echo -n "" > testPaths.log
echo -n "Searching"
# exec to feed pipe one by one
find ./../../../40_Implementation_test -type f -name Makefile -print -exec echo -n "" \; | while read path
do
    echo -n "."
    echo $path >> testPaths.log
done
echo ""

Thanks all for your help!

Sorry "vercsab" but the script just posted does not work because ${path} does not receive the filename from the find. The superfluous "-exec" parameters wreck the function of the script.
When dealing with unknown filenames in a script, always put them in double quotes.
(No comment about using complex relative paths because I guess that this was a quick test not a production script).
Hint: Using ${path} to contain a filename not a path obfuscates your code.

# Create an empty file
> testPaths.log
echo -n "Searching"
find ./../../../40_Implementation_test -type f -name Makefile -print | while read path
do
    echo -n "."
    echo "${path}" >> testPaths.log
done
echo ""

Footnote: I really think you need to read-up about pipelines. The "pipe" character "|" is not a sequential command separator in unix shell scripting (but the semi-colon character ";" is). The pipe characer "|" signifies that the output to STDOUT from the first command is to be fed directly into the input STDIN in the second command.

At my side code:

echo -n "" > testPaths.log
echo "Searching"
start=$(date +%s)
# exec to feed pipe one by one
find . -type f -name Makefile -print -exec echo -n "" \; | while read path
do
    echo "${path}" >> testPaths.log
    end=$(date +%s)
    diff=`expr $end - $start`
    echo "$path found in $diff seconds"
    start=$(date +%s)
done
# Output a linefeed 
echo ""
echo "Finished"

produced the output:

and code:

echo -n "" > testPaths.log
echo "Searching"
start=$(date +%s)
# exec to feed pipe one by one
find . -type f -name Makefile -print | while read path
do
    echo "${path}" >> testPaths.log
    end=$(date +%s)
    diff=`expr $end - $start`
    echo "$path found in $diff seconds"
    start=$(date +%s)
done
# Output a linefeed 
echo ""
echo "Finished"

produced the output:

Even if I

would you be so kind to explain why solution2 (preferred by you) is better for this issue? Thanks.