No! Not that shell!!!
My experience with dash has always been one of hatred. I didn’t quite felt the emotion myself, but I always felt that dash hated me and my scripts. Any script I would throw at it, it would chew back with tons of errors and I’d swear maybe even arrogance back at me. Being in such a situation with it, I was totally baffled that people could actually use that… devil shell!
In my scripts, to avoid the pain of it’s draconian touch I would usually do this :
case "$(readlink -f /proc/$$/exe)"; in
*dash)
echo "We don't support dash"
exit 1
;;
*)
sh="$(readlink -f /proc/$$/exe)"
;;
esac
I would then have the insurance that my scripts would not go through this (insert curse here) shell!
as I was working with jailTools, FrozenFox (A fellow friend on freenode’s IRC channel #xroutine) pointed out that I should try to stick as close as possible to POSIX compatible shells as to support as many shells as possible. To my bafflement FrozenFox mentionned the shell `dash’ as being one of the most POSIX conforming shell! So I took a (very) deep breath and decided to finally give that shell a chance. What seemed like mountains before were actually just technicalities after all. It turns out I wasn’t that far off from the POSIX style after all.
It turns out that the major “issue” with dash is the fact that it does not support the “function” bash way of creating functions.
Instead of doing :
function foo() {
..
}
We should do :
foo() {
..
}
With this change, the bulk of my scripts were actually working correctly! I could finally bury the hatchet of war and support dash. Sure, it doesn’t support any bashisms like Substring expansion, but that is easily fixed with sed.
Where we do this in bash :
a="thisVeryLongVar"; echo "${a:0:4}${a:8}"
Giving the result :
"thisLongVar"
We would need to create our own function using sed :
# substring offset <optional length> string
# cuts a string at the starting offset and wanted length.
substring() {
local init=$1; shift
if [ "$2" != "" ]; then toFetch="\(.\{$1\}\).*"; shift; else local toFetch="\(.*\)"; fi
echo "$1" | sed -e "s/^.\{$init\}$toFetch$/\1/"
}
a="thisVeryLongVar"; echo "$(substring 0 4 $a)$(substring 8 $a)"
And it would give the same result :
"thisLongVar"
A bit more code to do the same thing, but it should be portable to pretty much all the other shells out there.
Now the next issue was with the command `read’. Under dash read is not as featureful as in bash/zsh, under these, we could do :
read -d "" myList << EOF
entry one
entry two
entry three
EOF
In dash, read does not feature ‘-d’, but suprisingly we can do this instead :
myList=$(cat << EOF
entry one
entry two
entry three
EOF
)
and it accounts to exactly the same thing.
dash also doesn’t have the environment variable UID :
uid=$UID
so instead we use ‘id’ :
uid=$(id -u)
So the mountain I thought was the Everest, is now just a petty mound. A few changes and we can use this very fast shell. Sure, there’s nothing that will make someone actually use it as their actual command line shell as it doesn’t support a history and many other features we take for granted in the other shells. Let’s keep things to their strengths, shall we? Dash is meant for running scripts and it does it well.
I now converted jailTools to fully support dash thanks to these changes and they lived happily ever after, having the task to convert all of their scripts to support dash in the future. ^_^