0

I have a filenotfound script as follows:

# Check if filenames listed in a text file exist.
while read -r || [[ -n $REPLY ]]; do
    # Check if file (local or with full path) exists.
    [[ -f $REPLY ]] && continue

    # Filename with some wrong path.
    ... "long" processing (try to find file elsewhere, with same name)...
done

which I use in the following manner:

cat list-of-files.txt | filenotfound

and I would like to add a progress bar based on the number of lines given on stdin (so that the progress can be accurately monitored).

How can I count the number of lines from stdin, and let the while read loop operate on it? (without using temporary files, if possible)

PS- Code for progress bar to find at How to add a progress bar to a shell script?.

UPDATE -- Is it possible to not add a parameter to filenotfound, and get what I want through the usage of tee, subshells or things like that?

user3341592
  • 1,419
  • 1
  • 17
  • 36
  • You can't really get a progress bar for this logic, assuming you want to have some delay between one point to another, but this parsing of reading one line of stdin at a time happens much quickly and processing happens on it. So you wouldn't have a good progress bar just quick list of characters `....` for example unless you want to add a `sleep` between reading lines – Inian Aug 09 '17 at 12:06
  • The `list-of-files.txt` is a file containing, for example, 300 filenames. I want to check that all of them exist, one by one. When they don't, the script tries to find them elsewhere in some tree structure, using `find`, etc. So, _per filename processed_, the script can take around 1 sec to run, reason why a progress bar would be welcome. – user3341592 Aug 09 '17 at 12:09
  • In this case, I'd like to see the progress (in %) updated by one, every 3 filenames processed. – user3341592 Aug 09 '17 at 12:15

2 Answers2

0

You can use echo -ne to overwrite an existing line. You would need to wc -l the input file in order to know how many lines there are, and calculate how much precentage each line is. Then inside your for loop, do the precentage calculations and print it with echo -ne:

echo -ne '#####                     (33%)\r'
sleep 1
echo -ne '#############             (66%)\r'
sleep 1
echo -ne '#######################   (100%)\r'

This will print on the same line the progress.

EDIT: In order to implement that in your script, try the following:

num_lines=$1
each_row=$(echo "scale=2; (1/$num_lines) * 100" | bc)

function printProgress() {
        echo -ne "#"
}

for ((i=0;i<$num_lines;i++))
do
        # your code
        val=${each_row%.*}
        while [ $val -gt 0 ]; do
                printProg
                let "val--"
                sleep 1
        done
done

Then run your script with num of lines as your first arg, using cat list-of-files.txt | filenotfound $(wc -l list-of-files.txt)

Chen A.
  • 10,140
  • 3
  • 42
  • 61
  • I got that. The question is how to modify my script to get the number of lines in the file, and have the loop operate - when called by `cat list-of-files.txt | filenotfound` – user3341592 Aug 09 '17 at 12:35
  • I've added a sample code to my original post, let me know if this was what you were looking for – Chen A. Aug 09 '17 at 13:04
0

For a real progress bar (but not linear, as noted by Inian), you will have to modify your script such that it prints it. But in order to do so, it will also need to know beforehand the total number of entries. So, assuming there is one entry per line of list-of-files.txt, you could add an input parameter to your script and:

n=list-of-files.txt; cat $n | filenotfound $(wc -l $n)
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
  • Did not think that way, about adding a param. Isn't it possible to avoid it, with things such as `tee`, subshells or similar tools? Dunno, not enough experience. But that'd be really much better - but if it can't... – user3341592 Aug 09 '17 at 15:48
  • No, sorry, I do not see how to do that. But what's the problem, exactly? Why can't you do what I suggested? – Renaud Pacalet Aug 09 '17 at 16:02
  • For sure, I can. It simply that we need to duplicate the file name on the one-line command. Would be good to be able to avoid the repetition. – user3341592 Aug 09 '17 at 17:54
  • I know we can make another command from the above two, but I'm trying to keep the scripts callable in a series of piped commands. Reason why I'd have love to have no parameter, and use the original usage. – user3341592 Aug 09 '17 at 17:59
  • Well, use a variable, then (see my updated answer). And if you make a callable script of it, just replace `n` by `1` and it will be the first argument of your script call. – Renaud Pacalet Aug 10 '17 at 05:22