FIXME under construction

zenity --progress

The zenity command is intended to be used in shell scripts to obtain input via small Gnome dialog windows. It uses the newer 'long options' format (--) and returns results as strings and result codes. There are 10 different dialogs including one for --file-selection, --list (select from a list), --text (single line input), and --text-info (multiline input).

The --progress dialog produces a progress bar which can be finicky to get to update correctly.

The function below encapsulates the complex part of using zenity --progress.

The 'find' command returns all symbolic links found under the SDIR directory and directories under it on stdout which is piped to 'tee'. 'tee' duplicates stdout sending one copy to the guiProgress() process using the '>()' notation and passing the other on. stderr then gets redirected to a logfile and stdout is captured into the variable LINKS. If nothing was found, LINKS will be empty and fail the 'if [[ $LINKS ]]' test. The 'return $(true)' and 'return $(false)' insure that the the proper result code is set on return.

function guiProgress () {
  # 20110829, Robert C. Watson
  #
  # EXAMPLE USAGE...
  #
  #  SDIR=  ### starting directory for 'find' command
  #  FILE=  ### file that the symlinks point to
  #  LINKS= ### string containing the full pathname of every symlink pointing to FILE, separated by a space
  #
  #  LINKS=$(find -L "$SDIR" -xtype l -samefile "$FILE" -exec echo '{}' \; | tee >(guiProgress "Searching for links...") )  2>>$LOGFILE
  #  if [[ $LINKS ]]
  #  then
  #    do something with the list of links...
  #    return $(true)
  #  else
  #    log an error and take appropriate action...
  #    return $(false)
  #  fi
  #
  # A bug in zenity prevents pulsating or advancing the progress bar until it gets some kind of input so
  # we can introduce an 'echo' into the input stream with...
  #   cat <(echo) - | tee >(...)
  #
  # See EXPERIMENTS below
  #
  #
  # STEP-BY-STEP PROGRESS DIALOG
  #
  # Uses zenity to show a progress bar dialog that advances for each string
  # fed to it on stdin. First characters of the string are displayed above the
  # bar prefixed with a count. stdin is re-echoed to stdout for further
  # processing such as to capture output.
  #
  # NOTE: The piping and process substitution specifics are absolutely critical to make this work!
  #
  # OPTIONS
  #   -m {number}   Maximum value of progress bar. Defaults to 100.
  #                 If even an approximation of this can be supplied,
  #                 progress of the bar will more closely match reality.
  #
  # The process...
  #
  # - awk...
  # Prepend a record count to the input string.
  #   - each string (text between "") is treated by awk as a record
  #   - (NR/MAX)*100)%100 calculates what percentage to advance the bar
  #     - 'zenity --progress' takes stdin input like the following...
  #         1
  #         # string such as a filename
  #         2
  #         # string such as a filename
  #         :
  #         90
  #         # string such as a filename
  #         99
  #         # string such as a filename
  #     - The first of the two lines per input string is the percentage to
  #       advance and the second line is '#' followed by the text to display
  #
  # - | tee
  # Pipe awk output to 2 processes by duplicating it with 'tee'.
  #   - 'tee' outputs to both a file and to stdout whatever input it gets from the pipe.
  #   - to prevent dealing with creating and destroying a tmp file, we
  #     use Process Substitution to direct the output destined for a file
  #     instead to our zenity process.
  #   - the copy of the output going to stdout is automatically passed back
  #     to the calling function where it can be displayed or captured as in
  #       RESULT=$(ls | guiProgress -m 400 "Listing files...")
  #
  # --text="$(echo $TEXT | cut --characters=-160)..."
  # Limit displayed text to what will fit in the window.
  #   - 'zenity --progress' bombs if it tries to display too much much text.
  #   - there is no apparent limit on the amount it can be fed, just how much
  #     can be displayed.
  #
  # REFERENCE
  # - http://wiki.bash-hackers.org/howto/redirection_tutorial
  # - http://wiki.bash-hackers.org/syntax/expansion/proc_subst?s[]=process
  # - http://library.gnome.org/users/zenity/stable/zenity-usage.html.en
  # - http://stanley-huang.blogspot.com/search/label/Zenity
  #
  #
  local MAX=
  local TEXT=
  #
  # OPTIONAL
  #   $1 = -m
  #   $2 = {max-num-values}
  if [[ "$1" == "-m" ]]
  then
    MAX="$2"
    shift
  else
    MAX=100
  fi
  #
  TEXT="$*"
  #
  awk -v MAX=$MAX '{ print ((NR/MAX)*100)%100  "\n" "# " NR " of " MAX ": " $0 "\n" }' | tee >(zenity --progress  --title="$TITLE" --text="$(echo $TEXT | cut --characters=-160)..." --width="800" --auto-close --auto-kill)
  return $(true)
}

Experiments

Below are the experiments that led to the conclusions above. The result of each is noted at the beginning of its commented line of code.

  # EXPERIMENTS LEGEND
  # First Y/N  = pulsates; Second Y/N = passed string intact
  # A lowercase y/n means it partially worked.
  # Thus, from failure to success would be: N, n, y, Y
  #
  # 40 DOCUMENTED EXPERIMENTS...
  # YN: tee >(echo) | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NY: echo | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NN: tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NN: tee echo "10" | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # YN: tee >(echo "10") | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NN: cat | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NN: tee >(echo; zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NN: tee echo | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # nY: >(echo) | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # nY: >(echo; sleep 1) | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # nN: >(echo "20") | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NY: >(cat) | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NN: tee >(cat) | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NY: zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill
  # NY: >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NY: >(echo) > >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NY: >(echo) >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NN: echo >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NN: echo tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # nN: cat - | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NY: >(cat -) | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # N-: cat tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NY: echo | zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill <(echo)
  # NY: >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill) <(echo)
  # NY: >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill) <(echo -n)
  # NY: >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill) <(printf "")
  # NN: tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill) <(printf "")
  # YN: tee >(echo "") | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NY: >(echo "") | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NN: tee | tee >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NN: tee >(echo) >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NY: tee >(echo) | >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # --: tee (echo) | >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NY: tee >(echo "") | >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NY: tee >(echo) | >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # NY: tee >(echo; echo) | >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # nY: tee >(echo) | >(echo | zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  # yY: >(echo | zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill)
  #
  # per http://ubuntuforums.org/showthread.php?t=686757
  # nY: exec 3>&1 >(zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill); tee 1>&3; exec 3>&-
  #
  # [SOLVED (mostly)]
  # YY: cat <(echo) - | zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill
  #
  # 20110910-20110918
  # cat <(echo) - | zenity --progress --pulsate --title="$TITLE" --text="$TEXT" --auto-close --auto-kill
  # cat <( ((++i)); echo "$(($i / $#))"; sleep 1; ) - | zenity --progress --title="$TITLE" --text="$TEXT" --auto-close --auto-kill
  # cat <( awk -v LAST=$LASTMAX '{ print NR%100 "\n" "# " NR " of " LAST ": " $0 "\n" }'; sleep 1; ) - | zenity --progress --title="$TITLE" --text="$TEXT" --auto-close --auto-kill --width=900
  # cat <( awk -v LAST=$LAST -v MAX=$MAX '{ print "" MAX>0?((NR/MAX)*100):(NR%100) "\n" "# " NR " of " LAST ": " $0 "\n" }'; ) - | zenity --progress  --width="900" --title="$TITLE" --text="$TEXT" --auto-close --auto-kill
  # cat <( awk -v LAST=$LAST -v MAX=$MAX '{ print ((NR/MAX)*100)%100  "\n" "# " NR " of " LAST ": " $0 "\n" }'; ) - | zenity --progress  --width="800" --title="$TITLE" --text="$TEXT" --auto-close --auto-kill
  #
  # 20110919 These work but not fully functional
  # awk -v MAXTXT=$MAXTXT -v MAX=$MAX '{ print ((NR/MAX)*100)%100  "\n" "# " NR " of " MAXTXT ": " $0 "\n" }' | tee -a $LOGFILE | zenity --progress  --width="800" --title="$TITLE" --text="$TEXT" --auto-close --auto-kill
  # awk -v MAXTXT=$MAXTXT -v MAX=$MAX '{ print ((NR/MAX)*100)%100  "\n" "# " NR " of " MAXTXT ": " $0 "\n" }' | tee >(zenity --progress  --width="800" --title="$TITLE" --text="$TEXT" --auto-close --auto-kill) | grep --count ^#
  # awk -v MAXTXT=$MAXTXT -v MAX=$MAX '{ print ((NR/MAX)*100)%100  "\n" "# " NR " of " MAX ": " $0 "\n" }' | tee >(zenity --progress  --title="$TITLE" --text="$TEXT" --auto-close --auto-kill) | grep --count ^#
  # awk -v MAX=$MAX '{ print ((NR/MAX)*100)%100  "\n" "# " NR " of " MAX ": " $0 "\n" }' | tee >(zenity --progress  --title="$TITLE" --text="$TEXT" --width="800" --auto-close --auto-kill) | grep --count ^#

This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information
You could leave a comment if you were logged in.
  • zenity_--progress.txt
  • Last modified: 2011/10/11 12:45
  • by rcwatson