Shell (POSIX sh)

Variables & Quoting

name="world"
echo "Hello, $name"
echo "Hello, ${name}"
echo 'literal $name'

greeting="${name:-there}"
export PATH="$PATH:/usr/local/bin"
readonly CONST="value"
unset var

Strings

str="Hello World"
echo "${#str}"
echo "${str%World}"
echo "${str%%World}"
echo "${str#Hello}"
echo "${str##Hello}"
echo "${str/World/Bash}"

Conditionals (test/[ ])

if [ -f file.txt ]; then
    echo "regular file"
elif [ -d dir ]; then
    echo "directory"
else
    echo "not found"
fi

[ -n "$var" ]
[ -z "$var" ]
[ "$a" = "$b" ]
[ "$a" != "$b" ]
[ "$x" -gt "$y" ]
[ "$x" -lt "$y" ]
[ "$x" -eq "$y" ]
[ -r file ]
[ -w file ]
[ -x file ]
[ -s file ]

Loops

for item in one two three; do
    echo "$item"
done

for f in *.txt; do
    echo "$f"
done

while [ "$count" -lt 10 ]; do
    count=$((count + 1))
done

until [ -f /tmp/done ]; do
    sleep 1
done

Functions

greet() {
    echo "Hello, $1"
}

add() {
    echo $(($1 + $2))
}

result=$(add 3 5)

return_status() {
    return 1
}

Redirections

command > out.txt 2>&1
command >> out.txt
command 2>/dev/null
command >/dev/null 2>&1
command | tee output.txt
command1 | command2
cmd > out.txt 2> err.txt

Exit Codes

command
if [ $? -eq 0 ]; then
    echo "success"
else
    echo "failed with code $?"
fi

exit 0
exit 1

command && echo "ok" || echo "fail"

Positional Parameters

echo "script: $0"
echo "first: $1"
echo "second: $2"
echo "all: $@"
echo "count: $#"
echo "pid: $$"
echo "last exit: $?"
echo "background: $!"

shift
shift 2

Here Documents

cat <<EOF
multi line
text here
EOF

cat <<'EOF'
$not_expanded
EOF

variable=$(cat <<EOF
stored text
EOF
)

Arithmetic

echo $((1 + 2))
echo $((10 / 3))
echo $((2 ** 10))
echo $((x += 5))
echo $((x++))
echo $((x--))
echo $((x % 3))
echo $((x & 0xFF))

x=$((x + 1))

Pattern Matching (case)

case "$status" in
    running) echo "ok" ;;
    stopped) echo "down" ;;
    start*) echo "starts with start" ;;
    [0-9]*) echo "starts with digit" ;;
    *) echo "unknown" ;;
esac

case "$extension" in
    jpg|png|gif) echo "image" ;;
    mp4|avi) echo "video" ;;
    *) echo "other" ;;
esac

Signal Handling

trap 'echo "Interrupted"; exit 1' INT
trap 'rm -f /tmp/tempfile' EXIT
trap 'cleanup' TERM HUP

trap - INT

kill -l
kill -15 $PID
kill -9 $PID
wait $PID

Command Substitution

today=$(date +%Y-%m-%d)
files=$(ls *.txt)
lines=$(wc -l < file.txt)

result=$(echo "scale=2; 10/3" | bc)

dir=$(dirname "$0")
base=$(basename "$0")

Portability Tips

#!/bin/sh

[ "$var" = "yes" ]
[ -n "$var" ]
[ -z "$var" ]

echo "hello"
printf "name: %s\n" "$name"

[ x"$var" = x"yes" ]

command -v grep >/dev/null 2>&1 || { echo "grep required"; exit 1; }

: "${VAR:=default}"

变量与引用

name="world"
echo "Hello, $name"
echo "Hello, ${name}"
echo 'literal $name'

greeting="${name:-there}"
export PATH="$PATH:/usr/local/bin"
readonly CONST="value"
unset var

字符串

str="Hello World"
echo "${#str}"
echo "${str%World}"
echo "${str%%World}"
echo "${str#Hello}"
echo "${str##Hello}"
echo "${str/World/Bash}"

条件判断 (test/[ ])

if [ -f file.txt ]; then
    echo "regular file"
elif [ -d dir ]; then
    echo "directory"
else
    echo "not found"
fi

[ -n "$var" ]
[ -z "$var" ]
[ "$a" = "$b" ]
[ "$a" != "$b" ]
[ "$x" -gt "$y" ]
[ "$x" -lt "$y" ]
[ "$x" -eq "$y" ]
[ -r file ]
[ -w file ]
[ -x file ]
[ -s file ]

循环

for item in one two three; do
    echo "$item"
done

for f in *.txt; do
    echo "$f"
done

while [ "$count" -lt 10 ]; do
    count=$((count + 1))
done

until [ -f /tmp/done ]; do
    sleep 1
done

函数

greet() {
    echo "Hello, $1"
}

add() {
    echo $(($1 + $2))
}

result=$(add 3 5)

return_status() {
    return 1
}

重定向

command > out.txt 2>&1
command >> out.txt
command 2>/dev/null
command >/dev/null 2>&1
command | tee output.txt
command1 | command2
cmd > out.txt 2> err.txt

退出码

command
if [ $? -eq 0 ]; then
    echo "success"
else
    echo "failed with code $?"
fi

exit 0
exit 1

command && echo "ok" || echo "fail"

位置参数

echo "script: $0"
echo "first: $1"
echo "second: $2"
echo "all: $@"
echo "count: $#"
echo "pid: $$"
echo "last exit: $?"
echo "background: $!"

shift
shift 2

Here Document

cat <<EOF
multi line
text here
EOF

cat <<'EOF'
$not_expanded
EOF

variable=$(cat <<EOF
stored text
EOF
)

算术运算

echo $((1 + 2))
echo $((10 / 3))
echo $((2 ** 10))
echo $((x += 5))
echo $((x++))
echo $((x--))
echo $((x % 3))
echo $((x & 0xFF))

x=$((x + 1))

模式匹配 (case)

case "$status" in
    running) echo "ok" ;;
    stopped) echo "down" ;;
    start*) echo "starts with start" ;;
    [0-9]*) echo "starts with digit" ;;
    *) echo "unknown" ;;
esac

case "$extension" in
    jpg|png|gif) echo "image" ;;
    mp4|avi) echo "video" ;;
    *) echo "other" ;;
esac

信号处理

trap 'echo "Interrupted"; exit 1' INT
trap 'rm -f /tmp/tempfile' EXIT
trap 'cleanup' TERM HUP

trap - INT

kill -l
kill -15 $PID
kill -9 $PID
wait $PID

命令替换

today=$(date +%Y-%m-%d)
files=$(ls *.txt)
lines=$(wc -l < file.txt)

result=$(echo "scale=2; 10/3" | bc)

dir=$(dirname "$0")
base=$(basename "$0")

可移植性技巧

#!/bin/sh

[ "$var" = "yes" ]
[ -n "$var" ]
[ -z "$var" ]

echo "hello"
printf "name: %s\n" "$name"

[ x"$var" = x"yes" ]

command -v grep >/dev/null 2>&1 || { echo "grep required"; exit 1; }

: "${VAR:=default}"