In the yoga world, thereโs this concept called โdrishtiโโa focused gaze. Itโs not just about where you look during a pose, itโs about narrowing your attention to what truly matters, shedding the unnecessary to move with clarity and purpose. Think of a seasoned yogi in a crowded class: the room could be full of distractionsโmirrors, other people wobbling in Tree Poseโbut they stay laser-focused, breath aligned, body balanced, movement efficient.
This is Dash. In the chaotic world of scripting and system processes, Dash is that yogi. Minimal. Fast. Focused. It doesnโt care about fluffโitโs built to do one thing: run shell scripts quickly and efficiently.
Dash stands for Debian Almquist Shell. Itโs a lightweight, POSIX-compliant shell used primarily for scripting, not for interactive shell sessions like you might do in your terminal.
If youโve ever written a script and started it with:
#!/bin/sh
There's a good chance itโs actually being run by Dash on many Linux systems (especially Debian-based ones like Ubuntu). Thatโs because /bin/sh
on those systems often points to Dashโnot Bash.
Why? Because Dash is fast. It's streamlined to execute shell scripts more quickly than its bulkier siblings, which matters a lot when your system is booting or running hundreds of tiny scripts behind the scenes.
Letโs roll out the mat and get into the differences in style and purpose, yogi-style:
sh
), the standard for shell scripting./bin/sh
is just a symbolic link to either Dash, Bash, or another shell.Letโs say youโre just getting into scripting. You might not notice the milliseconds Dash saves at first. But imagine you're writing a script that runs every time your system boots, or every few minutes via cron. Multiply that over time, across hundreds of scriptsโthatโs impact.
Also, learning to write scripts that work in Dash (i.e., POSIX-compliant scripts) is a great habit. It forces you to keep things simple, portable, and robust. Itโs like learning to hold your Warrior II pose with precision before trying to fly into a handstand.
In yoga, the most advanced practitioners often return to the basicsโmastering the breath, the stillness, the form. Likewise, in scripting, sometimes the most efficient solution is the simplest one. Dash embodies that philosophy.
So if youโre just starting out with shell scripting, give Dash a try. Strip things back. Focus your gaze. Feel the breath of your system moving lighter and faster.
Namasteโand happy scripting with the examples below. โจ
Below is a top 100 list of common Dash shell scripting lines/blocks, tailored to beginners, but written with clarity and real-world relevance. These are all POSIX-compliant, meaning theyโll work in Dash (which doesn't support Bash-only features like arrays or syntax).
#!/bin/dash
NAME="Alice"
echo "Hello, $NAME"
if [ "$NAME" = "Alice" ]; then
echo "Welcome, Alice!"
fi
i=1
while [ "$i" -le 5 ]; do
echo "Loop $i"
i=$((i + 1))
done
for FILE in *.txt; do
echo "Found file: $FILE"
done
if [ -f "config.cfg" ]; then
echo "Config file exists."
fi
if [ -d "/etc" ]; then
echo "/etc exists."
fi
if [ -x "script.sh" ]; then
echo "Script is executable."
fi
uptime
echo "Something failed!" >&2
exit 1
echo "Enter your name:"
read USERNAME
echo "Hello, $USERNAME"
DATE=$(date)
echo "Today is $DATE"
echo "User input: "$USER_INPUT""
rm -f temp.txt
greet() {
echo "Hello, $1"
}
greet "Dash"
if [ "$USER" = "root" ]; then
echo "Running as root"
else
echo "Not root"
fi
if [ "$x" -gt 10 ]; then
echo "Greater than 10"
elif [ "$x" -eq 10 ]; then
echo "Exactly 10"
else
echo "Less than 10"
fi
some_command
if [ $? -eq 0 ]; then
echo "Success"
else
echo "Failed"
fi
echo "Log entry" >> logfile.txt
while IFS= read -r line; do
echo "Line: $line"
done < file.txt
if [ -z "$VAR" ]; then
echo "VAR is empty"
fi
if [ -n "$VAR" ]; then
echo "VAR is not empty"
fi
command 2> errors.txt
command > output.txt 2>&1
if command -v curl >/dev/null 2>&1; then
echo "curl is installed"
fi
if [ "$a" = "$b" ]; then
echo "Equal"
fi
if [ "$a" -lt 100 ]; then
echo "Less than 100"
fi
case "$1" in
start) echo "Starting...";;
stop) echo "Stopping...";;
*) echo "Usage: $0 {start|stop}";;
esac
echo "First arg: $1"
echo "All args: $@"
for ARG in "$@"; do
echo "Arg: $ARG"
done
i=5
i=$((i - 1))
sum=$((3 + 4))
echo "Sum: $sum"
&&
mkdir backup && echo "Directory created"
||
mkdir backup || echo "Failed to create directory"
if [ "$x" -gt 5 ] && [ "$x" -lt 10 ]; then
echo "x is between 6 and 9"
fi
while :; do
echo "Running forever"
sleep 1
done
cat <<EOF
Line 1
Line 2
EOF
if ! grep "word" file.txt; then
echo "Word not found"
fi
set -e
to Exit on Errorset -e
# Any command failing here will exit the script
set -u
to Error on Unset Variablesset -u
echo "$UNSET_VAR" # Will cause error if UNSET_VAR is undefined
ping -c 1 google.com >/dev/null 2>&1 && echo "Online"
sleep 5
if [ -s "file.txt" ]; then
echo "File has content"
fi
exec ./child_script.sh
DIR=$(cd "$(dirname "$0")" && pwd)
echo "Script is in $DIR"
if [ -w "/tmp" ]; then
echo "Writable"
fi
case $VAR in
''|*[!0-9]*) echo "Not a number" ;;
*) echo "Itโs a number" ;;
esac
.log
Filesrm -f *.log
TODAY=$(date +%F)
echo "Today is $TODAY"
if cmp -s file1.txt file2.txt; then
echo "Files are the same"
fi
LINES=$(wc -l < file.txt)
echo "Lines: $LINES"
START=$(date +%s)
your_command
END=$(date +%s)
echo "Took $((END - START)) seconds"
i=0
while [ "$i" -le 10 ]; do
echo "$i"
i=$((i + 2))
done
STR="hello"
i=0
while [ "$i" -lt "${#STR}" ]; do
echo "${STR:$i:1}"
i=$((i + 1))
done
โ ๏ธ Not POSIX โ string slicing like
${STR:$i:1}
isn't valid in Dash. A workaround would be needed. So this one should be skipped or rewritten usingcut
.
fold
echo "$STR" | fold -w1 | while read -r ch; do
echo "$ch"
done
> file.txt
exit 0
echo "New content" > file.txt
[ -d "logs" ] || mkdir logs
echo "You passed $# arguments."
You got it. Here's the next 40 Dash-compatible scripting lines/blocks, taking us from 61 to 100, with practical, real-world use still in focus โ no Bash-only features, strictly POSIX/Dash-safe.
seq
for i in $(seq 1 5); do
echo "Number: $i"
done
STR="hello"
STR="${STR} world"
echo "$STR"
echo "${NAME:-Guest}"
mkdir -p parent/child/grandchild
sed
TRIMMED=$(echo "$INPUT" | sed 's/^:space:*//;s/:space:*$//')
for f in *; do
echo "File: $f"
done
long_running_task &
long_running_task &
PID=$!
wait "$PID"
echo "Done"
trap 'echo "Exiting..."; cleanup' EXIT
trap 'echo "Interrupted!"; exit 1' INT
if grep -q "needle" haystack.txt; then
echo "Found it!"
fi
cp source.txt backup.txt
mv file.txt archive.txt
find . -type d -empty -delete
echo $((7 / 2)) # Outputs 3
USER=$(whoami)
if [ "${VAR+set}" = "set" ]; then
echo "VAR is set"
fi
command > out.txt
touch newfile.txt
ln -s /path/to/original linkname
if nc -z 127.0.0.1 80; then
echo "Port open"
fi
sed -i 's/old/new/g' file.txt
โ ๏ธ Use
sed -i ''
on macOS (not POSIX, but still widely used).
EXT="${FILE##*.}"
stty -echo -icanon time 0 min 1
read -r key
stty sane
if [ $# -eq 0 ]; then
echo "Usage: $0 <arg>"
exit 1
fi
if [ "$(id -u)" -eq 0 ]; then
echo "You are root"
fi
find . -name "*.log"
find . -type f -mtime +7 -exec rm {} ;
export API_KEY="abc123"
read -r FIRST < file.txt
i=0
while [ "$i" -lt 3 ]; do
echo "$i"
i=$((i + 1))
done
ps -ef
case "$1" in
yes) echo "You said yes" ;;
no) echo "You said no" ;;
*) echo "Unknown input" ;;
esac
if [ -n "$HOME" ]; then
echo "HOME is set"
fi
tar
tar czf archive.tar.gz folder/
.tar.gz
tar xzf archive.tar.gz
if [ "$#" -ne 2 ]; then
echo "Provide 2 arguments."
exit 1
fi
wget
wget https://example.com/file.txt
grep -i "error" logfile.txt
SCRIPT_NAME=$(basename "$0")
Want to make sure your script is truly Dash-compatible?
Run it like this explicitly:
dash your_script.sh