Question

I've written a simple script that uses 7zip to backup a directory. Everything works, but now I wanted to add some graphical feedback to it, adding a progress bar. I know that I can do this with zenity but, no matter what I try, I can't seem to make it work.

I am using fgrep to find out when a new file is being compressed ("Compressing" is the first word of every line printed on screen by 7zip) in order to make the bar increase. The specific line of code is the following:

7z a -t7z /home/user/Desktop/Backup.7z /home/user/Desktop/folder_to_backup -mx9 | fgrep Compressing | nl | awk '{print $1/$number_of_files*100}' | zenity --progress --percentage=0 --auto-close

Running this makes the progress bar appear, starting from 0, but no progress is shown: when the operation is complete, the bar suddenly jump to the end.

I've googled this for a while but the only thing I've found out is that zenity progress seems to have some problems :D Any help would be highly appreciated!

Was it helpful?

Solution

Looks like you are not getting the progress of the command in your output, check it out by running your command without the | zenity --progress --percentage=0 --auto-close pipe.

Try something like this to get your output, first you need to apt-get install screen if you don't have it installed:

screen -L bash -c '(while :; do tail ~/screenlog.0 | grep -o "[0-9]*%" | tail -1; done | zenity --progress --auto-close &); 7z a "output.zip" "/path/to/input"'

I'll break down the most important parts of the command:

  1. screen -L This flag tells the screen command to start a new session and log all terminal output to a file, ~/screenlog.0 by default.
  2. bash -c COMMAND1 Spawn a subshell and run COMMAND1 in it.
  3. (COMMAND2 &) Spawn another subshell that will launch COMMAND2 in the background.
  4. while :; Start an infinite loop.
  5. tail FILE Read last 10 lines of FILE.
  6. grep -o Print only the matched (non-empty) parts of a matching line.
  7. [0-9]*% Any series of digits followed by the % symbol.
  8. tail -1 Read last line of previous piped command.

OTHER TIPS

Solution without temporary file creation

Finally i got it after bash-headache and some nosebleed...

The clue is, interactive vs noninteractive buffering: Interactive programs generally line buffer their output; i.e., they write out every line. Noninteractive programs wait until they have a full buffer, which may be many lines of output. Now, if you pipe a noninteractive program to another program, the second program get its input not before the first program writes out the full buffer.

cd /home/user
export number_of_files=$(find folder_to_backup -type f | wc -l) && ( find folder_to_backup -print0 -type f -exec sh -c "7z a -t7z /path/to/Backup.7z {} -mx9 -bd | grep Compressing" \; | awk -W interactive -v x="$number_of_lines" '{printf "%d\n", (NR*100/x)}' ) | zenity --progress --percentage=0 --auto-close

I may need to explain:

  1. cd /home/user you need to cd in the folder from where you want the directory structure in the 7z-Backup, otherwise 7z puts no directory structure in the archive.

  2. export number_of_files=$(find folder_to_backup -type f | wc -l) first count the files to zip and export the variable for later calculations.

  3. find folder_to_backup -print0 -type f folder_to_backup MUST be a relative path. (see 1.)

  4. -exec sh -c "7z a -t7z /path/to/Backup.7z {} -mx9 -bd | grep Compressing" \; start a subshell for every line find puts out and execute 7z with a pipe to grep.

  5. awk -W interactive -v x="$number_of_lines" '{printf "%d\n", (NR*100/x)}' prompt awk to be interactive (-W interactive), propagate the previously exported variable (-v x="$number_of_lines"), and finally calculate and print the percentage ('{printf "%d\n", (NR*100/x)').

  6. Put all this in brackets and the pipe to zenity.

The problem is not with zenity. This is because 7z does not write to stdout. (probably deals with terminal directly, using tput or similar commands). thus you can not pipe it to another command.

you can actually see this if you redirect the command to a file:

 7z a -t7z /home/user/Desktop/Backup.7z /home/user/Desktop/folder_to_backup -mx9 | fgrep Compressing | nl | awk '{print $1}' > 7z.stdout

in my version of 7z the file looks like this:

7-Zip [64] 9.20  Copyright (c) 1999-2010 Igor Pavlov  2010-11-18
p7zip Version 9.20 (locale=en_CA.UTF-8,Utf16=on,HugeFiles=on,4 CPUs)

Scanning

Updating archive test.7z

Compressing  test.file

Everything is Ok

You will need a subshell with code to monitor the compression somehow, say by matching filesize with expected size at completion, and echoing a percentage. Put that subshell inside a subshell that is doing the compression. Visit http://user.cavenet.com/rolandl and check out ftp-user.txt for an example. Bash subshells are very handy!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top