[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] Cleanup, simplifications and bugfixes in scripts



* Thorsten Wißmann <edu _at_ thorsten _minus_ wissmann _dot_ de> [2013-06-25 09:39:14 +0200]:
> all in all, the patch is nice. I have some questions, for which I don't
> have a (best) answer yet.

By now, I probably do :)

Note this is still one big commit and not splitted in smaller ones,
but I hope that's okay, as there are too many changes which influence
others.

> On Thu, Jun 20, 2013 at 10:15:53PM +0200, Florian Bruhin wrote:
> >  herbstclient --idle '(tag_changed|goto_last_tag|reload)' \
> >      | while read line ; do
> > -        ARGS=( $line )
> > +        args=( $line )
> 
> Can we also use this read -a thing here?

I now switched all foo=( $bar ) to read -ra. (-r to not interpret
backslash escape sequences)
This also means the "set -f" is unneeded because with read -ra, globs
don't get expanded:

    $ touch boobs # SCNR
    $ str="foo *"
    $ arr1=( $str )
    $ read -ra arr2 <<< "$str"
    $ echo "${arr1[1]}"
    boobs
    $ echo "${arr2[1]}"
    *

> >  simple_command() {
> > -    arg=$($hc complete 1 "$@"|dmenu_cmd -p "$@:") \
> > -    && exec $hc "$@" "$arg"
> > +    arg=$("$hc" complete 1 "$@" | dmenu_cmd -p "$@:") \
> > +    && exec "$hc" "$@" "$arg"
> 
> > -$hc complete 1 use |
> > +"$hc" complete 1 use |
> >  while read tag ; do
> > [..]
> > -    $hc layout "$tag" \
> > +    "$hc" layout "$tag" \
> 
> > [similar hunks...]
> 
> My idea was to allow default arguments in herbstclient (maybe there will
> be a flag like --use-this-and-that-protocol in the future). So the
> decision is: Do we allow default arguments for herbstclient or allow
> spaces in the path of the herbstclient binary... (That's exactly the
> reason why hlwm-commands are arrays of strings and not just strings.)

As discussed with you in IRC, I replaced all the hc foo by this:

    hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;
    # ...
    hc do_something

This means:

 - Users can have herbstclient_command unset, then herbstclient gets used

 - Users can have herbstclient_command set to a string, then this gets called
   e.g. herbstclient_command=~/bin/herbstclient

 - Users can have herbstclient_command set to an array, e.g. for some future
   options, e.g.
   herbstclient_command=("/path with spaces/herbstclient" --some-option)

> > -function uniq_linebuffered() {
> > -    awk -W interactive '$0 != l { print ; l=$0 ; fflush(); }' "$@"
> > +uniq_linebuffered() {
> > +    awk -W interactive '$0 != l { print ; l=$0 ; fflush(); }' "$@" 2>/dev/null
> >  }
> 
> Why do you want to ignore stderr of awk? There are some versions of awk
> that do not support fflush(), so it may be useful if panel.sh would
> complain about that on stderr.

As discussed as well, now I'll leave stderr alone, but only set "-W
interactive" if using mawk.

Difference between this and the last patch summarized (running diff on commit
messages is kinda cool :P):

Everywhere:

 - Use "read -ra" to read fields into an array everywhere.

   This saves a "tr" call (in release.sh), only splits on the intended
   character (and not on any whitespace) and prevents accidental glob
   expansion.

   http://mywiki.wooledge.org/BashGuide/Arrays#line-81

 - Make calls of herbstclient/dmenu more consistent:

   If herbstclient_command is unset, "herbstclient" is called.

   If herbstclient_command is set to a string, the string is called.
   e.g.: herbstclient_command="$HOME/dev/herbstluftwm/herbstclient"

   If herbstclient_command is set to an array, the array is called.
   e.g.: herbstclient_command=("some path with spaces/herbstclient"
   "--some-future-option")

In herbstcommander.sh:

 - Rename dmenu_cmd to dmenu_command for consistency

In keychain.sh

 - Make modkey configurable, and use Mod1 instead of Mod4 by default

In panel.sh:

 - Remove "set -f" call, because this is now unneeded when switching to
   "read -ra" to fill arrays.

 - Read lines into cmd array directly

 - Only use "-W interactive" in uniq_linebuffered() when running mawk
   mawk needs this to line-buffer the output correctly, see
   http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=593504
   Other awk-versions (e.g. gawk) issue a warning, so we don't want to
   use it there.

 - Also use configured herbstclient call in clickable dzen area

Florian

-- 
www.the-compiler.org | Top-posting sucks! http://s.cmpl.cc/top
  I love long mails! | http://email.is-not-s.ms/
BOFH excuse #426: internet is needed to catch the etherbunny 
From 516f76c42fb6d05eec555c1d46d13096ead030a2 Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Tue, 18 Jun 2013 15:20:33 +0200
Subject: [PATCH] Cleanup, simplifications and bugfixes in scripts

Everywhere:

 - Replace all-caps variable names by lower-case ones, because upper-case
   variable names should be reserved for environment variables.

   http://stackoverflow.com/a/673940/2085149

 - Replace multiple sed calls to the same file with one sed-call with multiple
   -e arguments.

 - Use consistent spacing for pipes

 - Quote variables which could potentially have whitespace in them (monitor
   names, tag names, file paths)

   http://mywiki.wooledge.org/Quotes#line-28

 - Use "read -ra" to read fields into an array everywhere.

   This saves a "tr" call (in release.sh), only splits on the intended
   character (and not on any whitespace) and prevents accidental glob
   expansion.

   http://mywiki.wooledge.org/BashGuide/Arrays#line-81

 - Make calls of herbstclient/dmenu more consistent:

   If herbstclient_command is unset, "herbstclient" is called.

   If herbstclient_command is set to a string, the string is called.
   e.g.: herbstclient_command="$HOME/dev/herbstluftwm/herbstclient"

   If herbstclient_command is set to an array, the array is called.
   e.g.: herbstclient_command=("some path with spaces/herbstclient"
   "--some-future-option")

In release.sh:

 - Fix typo in comment

In dumpbeautify.sh:

 - Remove unneeded semicolons in awk script

 - Print color clear character directly from awk, saving a sed call

 - Print an additional clear after output is finished

 - Use & for the backreference for sed (faster, easier to read)

In exec_on_tag.sh:

 - Use "hc attr" to get current tag

In floatmon.sh:

 - Replace grep | cut | sed by single sed call

 - Check if xwininfo exists

In herbstcommander.sh:

 - Split tags up correctly (only by tab, not any whitespace)

 - Rename dmenu_cmd to dmenu_command for consistency

In keychain.sh

 - Make modkey configurable, and use Mod1 instead of Mod4 by default

In q3terminal.sh:

 - Bugfix: hc add "$tag", not scratchpad hardcoded

 - Don't use $ for variables inside ((..)) (consistency)

 - Add whitespace in calculations (easier to read)

In panel.sh:

 - Remove "set -f" call, because this is now unneeded when switching to
   "read -ra" to fill arrays.

 - Read lines into cmd array directly

 - Change geometry comment to reflect real monitor_rect output

 - Replace 'if [ -e "$(which foo)" ]' by simple 'if which foo'.
   which has an exit status saying if it has found anything or not, so there is
   no need to check it's output.

 - Use "foo()" instead of "function foo()"
   Consistency, and "function foo()" is not portable, not even across all bash
   versions.

   http://mywiki.wooledge.org/BashPitfalls#function_foo.28.29

 - Use \" instead of quote-mixing to get literal " inside "..." (easier to
   read)

 - Use simple sed call instead of cut | grep

 - Remove superfluous check if ${cmd[1]} is empty, as $monitor will never be
   empty.

 - Split tags up correctly (only by tab, not any whitespace)

 - Only use "-W interactive" in uniq_linebuffered() when running mawk
   mawk needs this to line-buffer the output correctly, see
   http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=593504
   Other awk-versions (e.g. gawk) issue a warning, so we don't want to
   use it there.

 - Also use configured herbstclient call in clickable dzen area
---
 release.sh                 | 34 +++++++++++++-------------
 scripts/dmenu.sh           | 12 +++------
 scripts/dumpbeautify.sh    | 56 +++++++++++++++++++++---------------------
 scripts/exec_on_tag.sh     | 22 ++++++-----------
 scripts/floatmon.sh        | 42 +++++++++++++++++++------------
 scripts/herbstcommander.sh | 29 +++++++++++++---------
 scripts/keychain.sh        |  9 ++++---
 scripts/lasttag.sh         | 13 +++++-----
 scripts/layout.sh          | 12 ++++-----
 scripts/loadstate.sh       |  6 ++---
 scripts/q3terminal.sh      | 33 +++++++++++--------------
 scripts/savestate.sh       |  6 ++---
 scripts/wselect.sh         |  9 ++++---
 share/panel.sh             | 61 ++++++++++++++++++++++++++--------------------
 share/restartpanels.sh     | 10 ++++----
 15 files changed, 185 insertions(+), 169 deletions(-)

diff --git a/release.sh b/release.sh
index 31ea228..4d72cda 100755
--- a/release.sh
+++ b/release.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-VERSION="$1"
+version="$1"
 
 if [ -z "$1" ] || [ "$1" = -h ] ; then
     echo "$0 VERSIONMAJOR.VERSIONMINOR.VERSIONPATCH"
@@ -13,47 +13,47 @@ if git status --porcelain | grep '^ M' ; then
     exit 1
 fi
 
-VERSIONARGS=( $(tr . ' ' <<< "$VERSION") )
+IFS=. read -ra versionargs <<< "$version"
 
 
 echo "==> Release commit"
 echo ":: Patching version.mk"
-sed -i "s/^VERSION_MAJOR.*$/VERSION_MAJOR = ${VERSIONARGS[0]}/" version.mk
-sed -i "s/^VERSION_MINOR.*$/VERSION_MINOR = ${VERSIONARGS[1]}/" version.mk
-sed -i "s/^VERSION_PATCH.*$/VERSION_PATCH = ${VERSIONARGS[2]}/" version.mk
+sed -i -e "s/^VERSION_MAJOR.*$/VERSION_MAJOR = ${versionargs[0]}/" \
+       -e "s/^VERSION_MINOR.*$/VERSION_MINOR = ${versionargs[1]}/" \
+       -e "s/^VERSION_PATCH.*$/VERSION_PATCH = ${versionargs[2]}/" version.mk
 
 echo ":: Patching NEWS"
 date=$(date +%Y-%m-%d)
-newheader="Release $VERSION on $date"
-newunderline="$(echo $newheader|sed 's/./-/g')"
+newheader="Release $version on $date"
+newunderline="$(echo $newheader | sed 's/./-/g')"
 headerexp="^Next Release: [^ ]*$"
-# this requires news sed
-sed -i -e "/$headerexp/,+1s/^[-]*$/$newunderline/" NEWS
-sed -i -e "s/$headerexp/$newheader/" NEWS
+# this requires new sed
+sed -i -e "/$headerexp/,+1s/^[-]*$/$newunderline/" \
+       -e "s/$headerexp/$newheader/" NEWS
 
 echo ":: Commiting changes"
 git add NEWS version.mk
-git commit -m "Release $VERSION"
+git commit -m "Release $version"
 echo ":: Tagging commit"
-git tag -s v$VERSION -m "Release $VERSION"
+git tag -s "v$version" -m "Release $version"
 
 echo "==> Tarball"
 echo ":: Tarball creation"
 make tar
-tarball=herbstluftwm-$VERSION.tar.gz
-md5sum=$(md5sum $tarball| head -c 13 )
+tarball="herbstluftwm-$version.tar.gz"
+md5sum=$(md5sum "$tarball" | head -c 13 )
 echo ":: Patching www/index.txt"
 line=$(printf "| %-7s | $date | $md5sum...%15s| link:tarballs/%s[tar.gz]" \
-                $VERSION                  ' '                 "$tarball" )
+                $version                  ' '                 "$tarball" )
 linerexp="// do not remove this: next version line will be added here"
 sed -i "s#^$linerexp\$#$line\n$linerexp#" www/index.txt
 echo ":: Commiting changes"
 git add www/index.txt
-git commit -m "www: Add $VERSION tarball"
+git commit -m "www: Add $version tarball"
 
 echo
 echo "Still to do:"
 echo "1. Add the following line to the MD5SUMS file on the mirror:"
-md5sum $tarball
+md5sum "$tarball"
 echo "2. Make www files and install them on the remote"
 echo "3. Push the changes to all public remotes (including --tags)"
diff --git a/scripts/dmenu.sh b/scripts/dmenu.sh
index 24bd556..053b45d 100755
--- a/scripts/dmenu.sh
+++ b/scripts/dmenu.sh
@@ -1,15 +1,11 @@
 #!/bin/bash
 
-dmenu_command=${dmenu_command:-dmenu}
-hc=${herbstclient_command:-herbstclient}
-
-dmenu_cmd() {
-    $dmenu_command "$@"
-}
+dm() { "${dmenu_command[@]:-dmenu}" "$@" ;}
+hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;}
 
 simple_command() {
-    arg=$($hc complete 1 "$@"|dmenu_cmd -p "$@:") \
-    && exec $hc "$@" "$arg"
+    arg=$(hc complete 1 "$@" | dm -p "$@:") \
+    && exec "${herbstclient_command[@]:-herbstclient}" "$@" "$arg"
 }
 
 simple_command "$1"
diff --git a/scripts/dumpbeautify.sh b/scripts/dumpbeautify.sh
index 3301306..423d167 100755
--- a/scripts/dumpbeautify.sh
+++ b/scripts/dumpbeautify.sh
@@ -7,54 +7,54 @@
 awkcode='
 BEGIN {
     indent=2
-    ORS="";
-    x=0;
-    open=0;
+    ORS=""
+    x=0
+    open=0
     first=1
-    i=0;
-    color[i++]="\033[1;31m";
-    color[i++]="\033[1;32m";
-    color[i++]="\033[1;33m";
-    color[i++]="\033[1;34m";
-    color[i++]="\033[1;35m";
-    color[i++]="\033[1;36m";
-    color[i++]="\033[1;37m";
-    color[i++]="\033[0;31m";
-    color[i++]="\033[0;32m";
-    color[i++]="\033[0;33m";
-    color[i++]="\033[0;34m";
-    color[i++]="\033[0;35m";
-    color[i++]="\033[0;36m";
-    color[i++]="\033[0;37m";
+    i=0
+    color[i++]="\033[1;31m"
+    color[i++]="\033[1;32m"
+    color[i++]="\033[1;33m"
+    color[i++]="\033[1;34m"
+    color[i++]="\033[1;35m"
+    color[i++]="\033[1;36m"
+    color[i++]="\033[1;37m"
+    color[i++]="\033[0;31m"
+    color[i++]="\033[0;32m"
+    color[i++]="\033[0;33m"
+    color[i++]="\033[0;34m"
+    color[i++]="\033[0;35m"
+    color[i++]="\033[0;36m"
+    color[i++]="\033[0;37m"
 }
 
 $1 ~ "^[(]" {
     if (first == 0) {
-        printf "\n";
-        printf "%"(indent*x)"s" , "" ;
+        printf "\n"
+        printf "%"(indent*x)"s" , ""
     } else {
-        first=0;
+        first=0
     }
     color_bracket[x]=open
     print color[(color_bracket[x]) % length(color)]
-    print ;
+    gsub("[(]", "&" clear)
+    print
     x++
-    open++;
+    open++
 }
 
 $1 ~ "[)]" {
-    x-- ;
+    x--
     print color[(color_bracket[x]) % length(color)]
     print
 }
 
 END {
-    printf "\n"
+    printf clear "\n"
 }
 '
 
 clear=$(tput sgr0) || clear=$(echo -e '\e[0m')
 
-sed 's/\([()]\)/\n\1/g' | # insert newlines before (
-    awk "$awkcode" |
-    sed 's#(#('"$clear"'#g'
+sed 's/[()]/\n&/g' | # insert newlines before (
+    awk -v "clear=$clear" "$awkcode"
diff --git a/scripts/exec_on_tag.sh b/scripts/exec_on_tag.sh
index 5c552db..f7acaa1 100755
--- a/scripts/exec_on_tag.sh
+++ b/scripts/exec_on_tag.sh
@@ -1,7 +1,9 @@
 #!/bin/bash
 
-TAG="$1"
-EXPIRE="120" # expiry time in seconds
+hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;}
+
+tag="$1"
+expire="120" # expiry time in seconds
 shift
 
 if [ -z "$1" ] ;then
@@ -12,22 +14,12 @@ if [ -z "$1" ] ;then
 
 fi
 
-hc() {
-    herbstclient "$@"
-}
-
-curtag() {
-     hc tag_status \
-        | grep -oE "$(echo -ne '\t')#[^$(echo -ne '\t')]*" \
-        | tail -c +3
-}
-
-TAG=${TAG:-$(curtag)}
+tag=${tag:-$(hc attr tags.focus.name)}
 
 # ensure tag exists
-hc add "$TAG"
+hc add "$tag"
 
 # move next window from this process to this tag
-hc rule maxage="$EXPIRE" pid="$$" tag="$TAG" once
+hc rule maxage="$expire" pid="$$" tag="$tag" once
 
 exec "$@"
diff --git a/scripts/floatmon.sh b/scripts/floatmon.sh
index 9f1f053..48cad41 100755
--- a/scripts/floatmon.sh
+++ b/scripts/floatmon.sh
@@ -5,23 +5,35 @@ tag=fl
 Mod=${Mod:-Mod1}
 Floatkey=${Floatkey:-Shift-f}
 
-hc() { herbstclient "$@" ; }
+hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;}
 
-size=$(xwininfo -root |
-                grep -E '^  (Width|Height):' |
-                cut -d' ' -f4 |
-                sed 'N;s/\n/x/')
+if which xwininfo &> /dev/null; then
+    size=$(xwininfo -root |
+           sed -n -e '/^  Width: / {
+                          s/.*: //;
+                          h
+                      }
+                      /^  Height: / {
+                          s/.*: //g;
+                          H;
+                          x;
+                          s/\n/x/p
+                      }')
+else
+    echo "This script requires the xwininfo binary."
+    exit 1
+fi
 
-hc chain , add $tag , floating $tag on
-hc or , add_monitor "$size"+0+0 $tag $monitor \
-      , move_monitor $monitor "$size"+0+0
-hc raise_monitor $monitor
-hc lock_tag $monitor
+hc chain , add "$tag" , floating "$tag" on
+hc or , add_monitor "$size"+0+0 "$tag" "$monitor" \
+      , move_monitor "$monitor" "$size"+0+0
+hc raise_monitor "$monitor"
+hc lock_tag "$monitor"
 
 cmd=(
 or  case: and
         # if not on floating monitor
-        . compare monitors.focus.name != $monitor
+        . compare monitors.focus.name != "$monitor"
         # and if a client is focused
         . get_attr clients.focus.winid
         # then remember the last monitor of the client
@@ -30,12 +42,12 @@ or  case: and
         . substitute M monitors.focus.index
             set_attr clients.focus.my_lastmon M
         # and then move the client to the floating tag
-        . shift_to_monitor $monitor
-        . focus_monitor $monitor
+        . shift_to_monitor "$monitor"
+        . focus_monitor "$monitor"
         . true
     case: and
         # if on the floating monitor
-        . compare monitors.focus.name = $monitor
+        . compare monitors.focus.name = "$monitor"
         # and if a client is focused
         . get_attr clients.focus.winid
         # then send it back to the original monitor
@@ -50,5 +62,5 @@ or  case: and
         . focus_monitor 0
 )
 
-herbstclient keybind $Mod-$Floatkey "${cmd[@]}"
+hc keybind $Mod-$Floatkey "${cmd[@]}"
 
diff --git a/scripts/herbstcommander.sh b/scripts/herbstcommander.sh
index 244d286..4698bb2 100755
--- a/scripts/herbstcommander.sh
+++ b/scripts/herbstcommander.sh
@@ -6,18 +6,25 @@
 # To customize dmenu-colors, create a file named "herbstcommander" in your
 # herbstluftwm config-directory, with something like this in it:
 #
-# dmenu_cmd="dmenu -i -b -nb #313131 -nf #686868 -sb #454545 -sf #898989"
+# dmenu_command=(dmenu -i -b -nb '#313131' -nf '#686868' -sb '#454545' -sf 
'#898989')
 #
 # You can also directly pass dmenu-arguments to this script instead, as long
-# as dmenu_cmd is undefined.
+# as dmenu_command is undefined.
 
 config_1="$XDG_CONFIG_HOME/herbstluftwm/herbstcommander"
 config_2="$HOME/.config/herbstluftwm/herbstcommander"
 [[ -f "$config_1" ]] && source "$config_1"
 [[ -f "$config_2" ]] && source "$config_2"
 
-dmenu_cmd=${dmenu_cmd:-dmenu -i}
-herbstclient_cmd=${herbstclient_cmd:-herbstclient}
+dm() {
+    if [[ "${dmenu_command[@]}" ]]; then
+        "${dmenu_command[@]}" "$@"
+    else
+        dmenu -i "$@"
+    fi
+}
+
+hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;}
 prompt=${prompt:-herbstluft: }
 display_reply=${display_reply:-true}
 
@@ -27,27 +34,27 @@ forceexec=0
 while :; do
     dmenu_args=""
     if [[ "$forceexec" != 1 ]]; then
-        completion=$($herbstclient_cmd complete "${#cmd[@]}" "${cmd[@]}")
+        completion=$(hc complete "${#cmd[@]}" "${cmd[@]}")
         if [[ "$?" = 7 ]] ; then
             forceexec=1
         fi
     fi
     if [[ "$forceexec" == 1 ]]; then
         echo "Executing ${cmd[@]}"
-        reply=$($herbstclient_cmd "${cmd[@]}")
+        reply=$(hc "${cmd[@]}")
         status=$?
         if [[ "$display_reply" && "$reply" ]]; then
-            $dmenu_cmd -p "${cmd[*]}" <<< "$reply" >/dev/null
+            dm -p "${cmd[*]}" <<< "$reply" >/dev/null
         fi
         exit $status
     else
         case "${cmd[*]}" in
             raise|jumpto|bring)
-                tags=( $($herbstclient_cmd tag_status) )
+                IFS=$'\t' read -ra tags <<< "$(hc tag_status)"
                 i=1
                 completion=$(
                     wmctrl -l | while read line; do
-                        fields=( $line )
+                        IFS=' ' read -ra fields <<< "$line"
                         id=${fields[0]}
                         tag=${tags[ ${fields[1]} ]}
                         class=$(xprop -notype -id $id WM_CLASS |
@@ -61,7 +68,7 @@ while :; do
                 dmenu_args="-l 10"
                 ;;
         esac
-        next=$($dmenu_cmd $dmenu_args -p "${prompt}${cmd[*]}" <<< 
"$completion")
+        next=$(dm $dmenu_args -p "${prompt}${cmd[*]}" <<< "$completion")
         (( $? != 0 )) && exit 125 # dmenu was killed
         if [[ -z "$next" ]]; then
             forceexec=1 # empty reply instead of completion
@@ -69,7 +76,7 @@ while :; do
             case "${cmd[*]}" in
                 raise|jumpto|bring)
                     # add the WINID only (second field)
-                    fields=( $next )
+                    IFS=' ' read -ra fields <<< "$next"
                     cmd+=( ${fields[1]} )
                     ;;
                 *)
diff --git a/scripts/keychain.sh b/scripts/keychain.sh
index 54c6618..1ac1c0f 100755
--- a/scripts/keychain.sh
+++ b/scripts/keychain.sh
@@ -3,16 +3,19 @@
 # Execute this (e.g. from your autostart) to obtain basic key chaining like it
 # is known from other applications like screen.
 #
-# E.g. you can press Mod4-i 1 (i.e. first press Mod4-i and then press the
+# E.g. you can press Mod1-i 1 (i.e. first press Mod1-i and then press the
 # 1-button) to switch to the first workspace
 #
 # The idea of this implementation is: If one presses the prefix (in this case
-# Mod4-i) except the notification, nothing is really executed but new
+# Mod1-i) except the notification, nothing is really executed but new
 # keybindings are added to execute the actually commands (like use_index 0) and
 # to unbind the second key level (1..9 and 0) of this keychain. (If you would
 # not unbind it, use_index 0 always would be executed when pressing the single
 # 1-button).
 
+hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;}
+Mod=Mod1
+
 # Create the array of keysyms, the n'th entry will be used for the n'th
 # keybinding
 keys=( {1..9} 0 )
@@ -27,7 +30,7 @@ done
 # key chain. (Except the spawn notify-send of course, which can be deactivated
 # by only deleting the appropriate line)
 
-herbstclient keybind Mod4-i chain \
+hc keybind $Mod-i chain \
     '->' spawn notify-send "Select a workspace number or press Escape" \
     '->' keybind "${keys[0]}" chain "${unbind[@]}" , use_index 0 \
     '->' keybind "${keys[1]}" chain "${unbind[@]}" , use_index 1 \
diff --git a/scripts/lasttag.sh b/scripts/lasttag.sh
index c329227..a6f951d 100755
--- a/scripts/lasttag.sh
+++ b/scripts/lasttag.sh
@@ -6,16 +6,17 @@
 # to switch to the last tag, call: herbstclient emit_hook goto_last_tag
 # or bind it: herbstclient keybind Mod1-Escape emit_hook goto_last_tag
 
-herbstclient --idle '(tag_changed|goto_last_tag|reload)' \
+hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;}
+hc --idle '(tag_changed|goto_last_tag|reload)' \
     | while read line ; do
-        ARGS=( $line )
-        case ${ARGS[0]} in
+        IFS=$'\t' read -ra args <<< "$line"
+        case ${args[0]} in
             tag_changed)
-                LASTTAG="$TAG"
-                TAG=${ARGS[1]}
+                lasttag="$tag"
+                tag=${args[1]}
                 ;;
             goto_last_tag)
-                ! [ -z "$LASTTAG" ] && herbstclient use "$LASTTAG"
+                [ "$lasttag" ] && hc use "$lasttag"
                 ;;
             reload)
                 exit
diff --git a/scripts/layout.sh b/scripts/layout.sh
index c631a84..fbac24f 100755
--- a/scripts/layout.sh
+++ b/scripts/layout.sh
@@ -3,14 +3,14 @@
 # print layout of all tags, and colorizes all window ids
 # it's useful to get a overview over the list of all windows
 
-hc=${herbstclient_command:-herbstclient}
+hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;}
 
-$hc complete 1 use |
+hc complete 1 use |
 while read tag ; do
     echo -n "$tag "
-    indent=$(echo -n "$tag "|sed 's/./ /g')
+    indent=$(echo -n "$tag " | sed 's/./ /g')
     # prepend indent, except in first line
-    $hc layout "$tag" \
-        | sed "2,\$ s/^/$indent/" \
-        | sed "s/\(0x[0-9a-f]\{1,\}\)/$(tput setaf 3)\1$(tput sgr0)/g"
+    hc layout "$tag" \
+        | sed -e "2,\$ s/^/$indent/" \
+              -e "s/0x[0-9a-f]\+/$(tput setaf 3)&$(tput sgr0)/g"
 done
diff --git a/scripts/loadstate.sh b/scripts/loadstate.sh
index 1c5e0a0..5a781f8 100755
--- a/scripts/loadstate.sh
+++ b/scripts/loadstate.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-hc=${herbstclient_command:-herbstclient}
+hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;}
 
 # loads layouts for each tag coming from stdin
 # the format is the one created by savestate.sh
@@ -13,6 +13,6 @@ hc=${herbstclient_command:-herbstclient}
 while read line ; do
     tag="${line%%: *}"
     tree="${line#*: }"
-    $hc add "$tag"
-    $hc load "$tag" "$tree"
+    hc add "$tag"
+    hc load "$tag" "$tree"
 done
diff --git a/scripts/q3terminal.sh b/scripts/q3terminal.sh
index 9d74580..bae9e89 100755
--- a/scripts/q3terminal.sh
+++ b/scripts/q3terminal.sh
@@ -13,27 +13,23 @@
 # If a tag name is supplied, this is used instead of the scratchpad
 
 tag="${1:-scratchpad}"
-
-hc() {
-    #echo "hc $@" >&2 ;
-    herbstclient "$@" ;
-}
+hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;}
 
 mrect=( $(hc monitor_rect -p "" ) )
-termwidth=$(((${mrect[2]}*8)/10))
+termwidth=$(( (${mrect[2]} * 8) / 10 ))
 termheight=400
 
 rect=(
     $termwidth
     $termheight
-    $((${mrect[0]}+(${mrect[2]}-termwidth)/2))
-    $((${mrect[1]}-termheight))
+    $(( ${mrect[0]} + (${mrect[2]} - termwidth) / 2 ))
+    $(( ${mrect[1]} - termheight ))
 )
 
 y_line=${mrect[1]}
 
 
-hc add scratchpad
+hc add "$tag"
 
 
 monitor=q3terminal
@@ -45,9 +41,9 @@ if ! hc add_monitor $(printf "%dx%d%+d%+d" "${rect[@]}") \
 else
     # remember which monitor was focused previously
     hc chain \
-        , new_attr string monitors.by-name.$monitor.my_prev_focus \
+        , new_attr string monitors.by-name."$monitor".my_prev_focus \
         , substitute M monitors.focus.index \
-            set_attr monitors.by-name.$monitor.my_prev_focus M
+            set_attr monitors.by-name."$monitor".my_prev_focus M
 fi
 
 update_geom() {
@@ -61,19 +57,18 @@ interval=0.01
 animate() {
     progress=( "$@" )
     for i in "${progress[@]}" ; do
-        rect[3]=$((${y_line}-(i*termheight)/$steps))
+        rect[3]=$((y_line - (i * termheight) / steps))
         update_geom
         sleep "$interval"
     done
 }
 
 show() {
-
     hc lock
-    hc raise_monitor $monitor
-    hc focus_monitor $monitor
+    hc raise_monitor "$monitor"
+    hc focus_monitor "$monitor"
     hc unlock
-    hc lock_tag $monitor
+    hc lock_tag "$monitor"
     animate $(seq $steps -1 0)
 }
 
@@ -91,10 +86,10 @@ hide() {
     animate $(seq 0 +1 $steps)
     # if q3terminal still is focused, then focus the previously focused monitor
     # (that mon which was focused when starting q3terminal)
-    hc substitute M monitors.by-name.$monitor.my_prev_focus \
-        and + compare monitors.focus.name = $monitor \
+    hc substitute M monitors.by-name."$monitor".my_prev_focus \
+        and + compare monitors.focus.name = "$monitor" \
             + focus_monitor M
-    hc remove_monitor $monitor
+    hc remove_monitor "$monitor"
 }
 
 [ $exists = true ] && hide || show
diff --git a/scripts/savestate.sh b/scripts/savestate.sh
index b717f46..74e597b 100755
--- a/scripts/savestate.sh
+++ b/scripts/savestate.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-hc=${herbstclient_command:-herbstclient}
+hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;}
 
 # prints a machine readable format of all tags and its layouts
 # one tag with its layout per line
@@ -10,8 +10,8 @@ hc=${herbstclient_command:-herbstclient}
 # and sometime later:
 # loadstate.sh < mystate
 
-$hc complete 1 use |
+hc complete 1 use |
 while read tag ; do
     echo -n "$tag: "
-    $hc dump "$tag"
+    hc dump "$tag"
 done
diff --git a/scripts/wselect.sh b/scripts/wselect.sh
index 5a31d69..de45d4c 100755
--- a/scripts/wselect.sh
+++ b/scripts/wselect.sh
@@ -4,7 +4,8 @@
 # dependencies: wmctrl, awk,
 #               dmenu with multiline support (command line flag -l)
 
-dmenu_command=${dmenu_command:-dmenu}
+hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;}
+dm() { "${dmenu_command[@]:-dmenu}" "$@" ;}
 dmenu_lines=${dmenu_lines:-10}
 
 case "$1" in
@@ -12,16 +13,16 @@ case "$1" in
     bring)
         # bring the selected window to the current tag and focus it
         name=Bring:
-        action() { herbstclient bring "$@" ; }
+        action() { hc bring "$@" ; }
         ;;
 
     select|*)
         # switch to the selected window and focus it
-        action() { herbstclient jumpto "$@" ; }
+        action() { hc jumpto "$@" ; }
         name=Select:
         ;;
 esac
 
 id=$(wmctrl -l |cat -n| sed 's/\t/) /g'| sed 's/^[ ]*//' \
-    | $dmenu_command -l $dmenu_lines -p "$name") \
+    | dm -l $dmenu_lines -p "$name") \
     && action $(awk '{ print $2 ; }' <<< "$id")
diff --git a/share/panel.sh b/share/panel.sh
index 5dcfec8..93cf1c9 100755
--- a/share/panel.sh
+++ b/share/panel.sh
@@ -1,31 +1,28 @@
 #!/bin/bash
 
-# disable path name expansion or * will be expanded in the line
-# cmd=( $line )
-set -f
-
+hc() { "${herbstclient_command[@]:-herbstclient}" "$@" ;}
 monitor=${1:-0}
 geometry=( $(herbstclient monitor_rect "$monitor") )
 if [ -z "$geometry" ] ;then
     echo "Invalid monitor $monitor"
     exit 1
 fi
-# geometry has the format: WxH+X+Y
+# geometry has the format W H X Y
 x=${geometry[0]}
 y=${geometry[1]}
 panel_width=${geometry[2]}
 panel_height=16
 font="-*-fixed-medium-*-*-*-12-*-*-*-*-*-*-*"
-bgcolor=$(herbstclient get frame_border_normal_color)
-selbg=$(herbstclient get window_border_active_color)
+bgcolor=$(hc get frame_border_normal_color)
+selbg=$(hc get window_border_active_color)
 selfg='#101010'
 
 ####
 # Try to find textwidth binary.
 # In e.g. Ubuntu, this is named dzen2-textwidth.
-if [ -e "$(which textwidth 2> /dev/null)" ] ; then
+if which textwidth &> /dev/null ; then
     textwidth="textwidth";
-elif [ -e "$(which dzen2-textwidth 2> /dev/null)" ] ; then
+elif which dzen2-textwidth &> /dev/null ; then
     textwidth="dzen2-textwidth";
 else
     echo "This script requires the textwidth tool of the dzen2 project."
@@ -41,23 +38,33 @@ else
     dzen2_svn=""
 fi
 
-function uniq_linebuffered() {
-    awk -W interactive '$0 != l { print ; l=$0 ; fflush(); }' "$@"
-}
+if awk -Wv 2>/dev/null | head -1 | grep -q '^mawk'; then
+    # mawk needs "-W interactive" to line-buffer stdout correctly
+    # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=593504
+    uniq_linebuffered() {
+      awk -W interactive '$0 != l { print ; l=$0 ; fflush(); }' "$@"
+    }
+else
+    # other awk versions (e.g. gawk) issue a warning with "-W interactive", so
+    # we don't want to use it there.
+    uniq_linebuffered() {
+      awk '$0 != l { print ; l=$0 ; fflush(); }' "$@"
+    }
+fi
 
-herbstclient pad $monitor $panel_height
+hc pad $monitor $panel_height
 {
     # events:
     #mpc idleloop player &
     while true ; do
         date +'date ^fg(#efefef)%H:%M^fg(#909090), %Y-%m-^fg(#efefef)%d'
         sleep 1 || break
-    done > >(uniq_linebuffered)  &
+    done > >(uniq_linebuffered) &
     childpid=$!
-    herbstclient --idle
+    hc --idle
     kill $childpid
 } 2> /dev/null | {
-    TAGS=( $(herbstclient tag_status $monitor) )
+    IFS=$'\t' read -ra tags <<< "$(hc tag_status $monitor)"
     visible=true
     date=""
     windowtitle=""
@@ -65,7 +72,7 @@ herbstclient pad $monitor $panel_height
         bordercolor="#26221C"
         separator="^bg()^fg($selbg)|"
         # draw tags
-        for i in "${TAGS[@]}" ; do
+        for i in "${tags[@]}" ; do
             case ${i:0:1} in
                 '#')
                     echo -n "^bg($selbg)^fg($selfg)"
@@ -84,7 +91,10 @@ herbstclient pad $monitor $panel_height
                     ;;
             esac
             if [ ! -z "$dzen2_svn" ] ; then
-                echo -n "^ca(1,herbstclient focus_monitor $monitor && 
"'herbstclient use "'${i:1}'") '"${i:1} ^ca()"
+                echo -n "^ca(1,\"${herbstclient_command[@]:-herbstclient}\" "
+                echo -n "focus_monitor \"$monitor\" && "
+                echo -n "\"${herbstclient_command[@]:-herbstclient}\" "
+                echo -n "use \"${i:1}\") ${i:1} ^ca()"
             else
                 echo -n " ${i:1} "
             fi
@@ -93,19 +103,18 @@ herbstclient pad $monitor $panel_height
         echo -n "^bg()^fg() ${windowtitle//^/^^}"
         # small adjustments
         right="$separator^bg() $date $separator"
-        right_text_only=$(echo -n "$right"|sed 's.\^[^(]*([^)]*)..g')
+        right_text_only=$(echo -n "$right" | sed 's.\^[^(]*([^)]*)..g')
         # get width of right aligned text.. and add some space..
         width=$($textwidth "$font" "$right_text_only    ")
         echo -n "^pa($(($panel_width - $width)))$right"
         echo
         # wait for next event
-        read line || break
-        cmd=( $line )
+        IFS=$'\t' read -ra cmd || break
         # find out event origin
         case "${cmd[0]}" in
             tag*)
                 #echo "resetting tags" >&2
-                TAGS=( $(herbstclient tag_status $monitor) )
+                IFS=$'\t' read -ra tags <<< "$(hc tag_status $monitor)"
                 ;;
             date)
                 #echo "resetting date" >&2
@@ -115,8 +124,8 @@ herbstclient pad $monitor $panel_height
                 exit
                 ;;
             togglehidepanel)
-                currentmonidx=$(herbstclient list_monitors |grep ' 
\[FOCUS\]$'|cut -d: -f1)
-                if [ -n "${cmd[1]}" ] && [ "${cmd[1]}" -ne "$monitor" ] ; then
+                currentmonidx=$(hc list_monitors | sed -n 
'/\[FOCUS\]$/s/:.*//p')
+                if [ "${cmd[1]}" -ne "$monitor" ] ; then
                     continue
                 fi
                 if [ "${cmd[1]}" = "current" ] && [ "$currentmonidx" -ne 
"$monitor" ] ; then
@@ -125,10 +134,10 @@ herbstclient pad $monitor $panel_height
                 echo "^togglehide()"
                 if $visible ; then
                     visible=false
-                    herbstclient pad $monitor 0
+                    hc pad $monitor 0
                 else
                     visible=true
-                    herbstclient pad $monitor $panel_height
+                    hc pad $monitor $panel_height
                 fi
                 ;;
             reload)
diff --git a/share/restartpanels.sh b/share/restartpanels.sh
index 320a3fe..9d9110c 100755
--- a/share/restartpanels.sh
+++ b/share/restartpanels.sh
@@ -2,15 +2,15 @@
 
 installdir=/
 
-XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
+XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
 defaultpanel="$XDG_CONFIG_HOME/herbstluftwm/panel.sh"
 
-[ -x "$defaultpanel" ] || 
defaultpanel=$installdir/etc/xdg/herbstluftwm/panel.sh
+[ -x "$defaultpanel" ] || 
defaultpanel="$installdir/etc/xdg/herbstluftwm/panel.sh"
 
-panelcmd=${1:-$defaultpanel}
+panelcmd="${1:-$defaultpanel}"
 
 herbstclient emit_hook quit_panel
 
-for i in $(herbstclient list_monitors|cut -d':' -f1) ; do
-    $panelcmd $i &
+for i in $(herbstclient list_monitors | cut -d':' -f1) ; do
+    "$panelcmd" $i &
 done
-- 
1.8.3.4

Attachment: pgpdahTLuFUkb.pgp
Description: PGP signature