Home > front end >  How do I continuously print a file(to terminal) being written to from another script?
How do I continuously print a file(to terminal) being written to from another script?

Time:08-29

Say I have a script that is reading from a file being printed to. In other words, I have Script A running, which prints its progress in a percentage i.e. 40%. Script A does this until 100% is reached. The file name being printed to is File_A. Script B looks like the following:

$pid=script A process ID

trap "kill $pid 2> /dev/null" EXIT

percent=$(cat File_A | tail -n 1)

while kill -0 $pid 2> /dev/null ; do printf "\r%s" "$percent" ; sleep 1 ; ((n  )) ; done

The result I get from Script B is a line that prints the same percentage; the percentage doesn't change. For example, the terminal looks like so: 40%

It stays at 40%(an arbitrary number I picked for the sake of using an example). EVEN THOUGH Script A is still running AND printing to File_A; the percent in the file is updating, but Script B won't print these new lines.

I am not sure how to get Script B to print the updated lines in File_A. I'm assuming it has something to do with different shell sessions, but I wouldn't know exactly what question to ask in regards to that; So how can I solve this?

CodePudding user response:

The primary problem here is that you set percent once at the beginning, and never update it. You'd need to put percent=$(cat File_A | tail -n 1) inside the loop to get it to update each time.

But there's a second problem, which won't prevent it from working, but makes it inefficient (especially if it runs that command over and over and over). The construct cat somefile | somecommand is what's sometimes called a "useless use of cat", because cat isn't doing anything useful here -- the next program in the pipe can read from the file perfectly well by itself, it doesn't need cat to preprocess it. In this case, using cat here isn't just useless, it makes tail less efficient. Compare these two commands:

tail -n 1 File_A        # tail reads directly from File_A
cat File_A | tail -n 1  # tail reads from a pipe from cat

In the first version, since tail has direct access to the file, it can basically start reading the file from the end until it has the last line, print that, and be done. In the version with cat, it cannot do this, since cat sends the file in order. So in the second version, tail (and cat) must read through the entire file, just to ignore all but the last line.

So this would be a much better way to do it:

n=1

while [ $n -le 100 ] ; do
    percent=$(tail -n 1 File_A)
    printf "\r%s" "$percent"
    sleep 1
    ((n  ))
done

But there's another method that might work better. Rather than re-checking the file constantly, you could use tail -f to "follow" the file and get updates when it changes. However, there's a difficulty here that it doesn't know when to stop reading (i.e. when the output has finished), so you have to figure out how to detect that and exit the loop. Something like this might work:

tail -n 1 -f File_A | while read percent; do
    printf "\r%s" "$percent"
    [[ "$percent" = "100" ]] && break
done

(Note that if the actual final output is something like "100%" instead of just "100", you'd have to change that comparison appropriately.)

  •  Tags:  
  • bash
  • Related