3

As GNU parallel's manual shows, you can use a zenity progress bar with parallel:

seq 1000 | parallel -j30 --bar '(echo {};sleep 0.1)' \
    2> >(zenity --progress --auto-kill) | wc

However, in that example, the cancel button doesn't work. I've read about similar issues with this button when used with more usual commands (i.e. not parallel) as well as some more insight about how that cancel button works but that didn't really help me. Parallel seems to make use of it quite differently and I can't figure out how to get that cancel button to stop the process.

I'm mostly confused by the 2> > and the wc. If I just use a | instead, the cancel button works but now the progress bar goes faster and finishes too early (I guess it only shows the progress of the first split part of the job? But if that was the case it should be 30 times faster, which it's not, so I'm not sure).

PS: Just to let you know, I've told about this issue on the parallel mailing list.

  • Sure. I updated the question and added some more info. Thanks for trying to help. – ChameleonScales Jul 20 '20 at 20:14
  • 1
    I think `seq 1000|parallel -j3 --bar '(echo {};sleep 0.1)' 2>&1 1>/dev/null|zenity --progress` is basically the same as the original command (without the `wc`), but Cancel does not work. On the other hand, removing `1>/dev/null` (thus redirecting both stderr and stdin to zenity) results in Cancel working. I must be missing something, maybe someone can catch on this hint and be able to write an answer. – Quasímodo Jul 20 '20 at 21:38

2 Answers2

3

Zenity is desinged to read two lines, one for progress bar and one begining with "#" for progress text:

for ((i=0;i<=100;i++));do
  echo "$i"                  # bar
  echo "#percent done $i"    # text
  sleep .1
done
| zenity --progress

I guess that --bar option writes progress to stderr but doesn't close it or doesn't write a newline character at the end of the line. That blocks zenity which expects a new line. The workaround is to print newline to stderr which is file descriptor 2 by default.

seq 1000 | parallel -j30 --bar '(echo {}; echo >&2; sleep 0.1)' \
    2> >(zenity --progress --auto-kill) | wc
  • Thank you! Do you think this could be added to the manual? – ChameleonScales Jul 21 '20 at 07:29
  • ok wait... What does >&2 do exactly? – ChameleonScales Jul 21 '20 at 09:25
  • >&2 is redirecting stdout to file descriptor "2" meaning stderr. All normal output from the command will be sent to stderr. [gnu.org Redirections](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Redirections) – Miloš Pavlović Jul 21 '20 at 10:36
  • Either added to the manual or developers could fix it since the manual claims it is compatible with zenity. On the other hand, it could be a bug with zenity. Same thing happens with yad (yet another dialog) progress bar, and yad is a fork of zenity. – Miloš Pavlović Jul 21 '20 at 10:50
1

So apparently zenity wants a newline for Cancel to work.

GNU Parallel's --bar uses \r in its output, which works great for the progress bar in zenity, but surprisingly not for the Cancel button.

One obvious solution is therefore to replace \r with \n before feeding it to zenity if you need the Cancel button:

seq 1000 |
  parallel -j30 --bar '(echo {}; sleep 0.1)' 2> >(perl -pe 'BEGIN{$/="\r";$|=1};s/\r/\n/g' |
    zenity --progress --auto-kill) |
  wc

A less obvious solution is to use strace and trace for something that never happens:

seq 1000 |
  parallel -j30 --bar '(echo {};sleep 0.1)' 2> >(strace -e trace=creat zenity --progress --auto-kill) |
  wc

I have absolutely no idea why strace makes this work.

Ole Tange
  • 33,591
  • 31
  • 102
  • 198
  • hehe ok, so it seems I found a weird one. Thanks for helping. On my side, your first bit of code makes a progress bar that stays at 0 until it hits 100% but anyway, I have 2 working solutions couting Miloš Pavlović's so that's fine. – ChameleonScales Jul 21 '20 at 18:11
  • 1
    @ChameleonScales Sorry. A random : somehow sneaked in. Fixed. – Ole Tange Jul 21 '20 at 19:57
  • cool. So now I'm wondering, do you think there's a benefit to using one of your commands instead of Miloš Pavlović's? So far they all seem to work the same for me but I don't know if one of them is a better/safer solution. – ChameleonScales Jul 24 '20 at 07:15
  • 1
    There is not really a huge difference. I have found a small difference: If you use `--files` my solutions will work, whereas Miloš' solution will not. Otherwise I will consider it a matter of taste. – Ole Tange Jul 24 '20 at 16:51
  • The first one will not continue after clicking on OK. `seq 100 | parallel -j30 --bar '(echo {}; sleep 0.1)' 2> >(perl -pe 'BEGIN{$/="\r";$|=1};s/\r/\n/g' | zenity --progress --auto-kill && zenity --about) | wc` Works with strace. Strace probably does line buffering. – Miloš Pavlović Jul 27 '20 at 20:03
  • @MilošPavlović It works for me. If I run the command you give, I can click OK and then `zenity --about` runs. `perl` flushes the buffer for each print due to `$|=1`. – Ole Tange Jul 27 '20 at 20:41
  • @OleTange weird, also the cancel button should be greyed out when the bar reaches 100%. Had to resort to closing stdin when the bar reaches 100. `seq 100 | parallel -j30 --bar '(echo {} >&2; echo {}; sleep 0.1)' 2> >(while read line 2>/dev/null; do echo "#Working${line#*'#'}"; [[ "$line" =~ "100%" ]] && echo "#All done" && exec <&-; done | zenity --progress --auto-kill && zenity --about) | wc` – Miloš Pavlović Jul 27 '20 at 21:04