Skip to content

Instantly share code, notes, and snippets.

@janaz
Created March 3, 2019 06:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save janaz/c4bd909651e6da3a5d1ab16a67c0517c to your computer and use it in GitHub Desktop.
Save janaz/c4bd909651e6da3a5d1ab16a67c0517c to your computer and use it in GitHub Desktop.
Daemons in Bash
#!/bin/bash
SLEEP=0.005
COLS=$(tput cols)
ROWS=$(tput lines)
RED="\033[0;31m"
YELLOW="\033[0;33m"
GREEN="\033[0;32m"
BLUE="\033[0;34m"
CYAN="\033[1;36m"
MY_BLUE="\033[1;34m"
LIGHT_RED="\033[1;31m"
LIGHT_GREEN="\033[1;32m"
WHITE="\033[1;37m"
LIGHT_GRAY="\033[0;36m"
MY_RED="\033[0;31m"
COLOR_NONE="\e[0m"
function center_one() {
local foo="$1"
for (( i=0; i<$((($COLS - ${#foo}) / 2)); i++)); do
printf " "
done
write_one "$foo"
}
function write_one() {
local foo="$1"
for (( i=0; i<${#foo}; i++ )); do
if [ "${foo:$i:1}" == "%" ]; then
printf "%%"
else
printf "${foo:$i:1}"
fi
if [ "${foo:$i:1}" != " " ]; then
sleep $SLEEP
fi
done
echo
}
function center() {
echo "$1" |while read l; do
center_one "$l"
done
}
function write() {
echo "$1" |while read l; do
write_one "$l"
done
}
function wait_key_press() {
read -n1 -s x
if [ "$x" == "p" -o "$x" == "P" -o "$x" == "[" -o "$x" == "{" -o "$x" == "," -o "$x" == "<" ]; then
echo "P"
else
echo "N"
fi
}
function finish_page() {
local cur_row=$1
while [ "$cur_row" -lt "$ROWS" ]; do
echo
sleep $SLEEP
cur_row=$(($cur_row + 1))
done
}
function breaks() {
local cur_row=0
while [ "$cur_row" -lt "$1" ]; do
echo
sleep $SLEEP
cur_row=$(($cur_row + 1))
done
}
function page_1() {
write_one
center "D A E M O N S I N B A S H"
center "‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾"
breaks 6
center "Tomasz Janowski"
finish_page 11
n=$(wait_key_press)
}
function page_1a {
write_one
center "BASH"
center "‾‾‾‾"
breaks 5
write_one " Bash is a command processor that typically runs in a text"
write_one " window, where the user types commands that cause actions."
write_one
write_one " Bash can also read commands from a file, called a script."
write_one " Like all Unix shells, it supports filename wildcarding,"
write_one " piping, here documents, command substitution, variables"
write_one " and control structures for condition-testing and iteration."
breaks 3
printf "${BLUE}"
center_one "http://en.wikipedia.org/wiki/Bash_(Unix_shell)"
printf "$COLOR_NONE"
finish_page 20
n=$(wait_key_press)
}
function page_2() {
write_one
center "PRESENTATIONS IN BASH"
center "‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾"
breaks 6
write_one " ★ Presentation as a code"
write_one " ★ High contrast"
printf " ★ ${RED}C${CYAN}O${YELLOW}L${BLUE}O${GREEN}R${MY_RED}S ${YELLOW}! ${COLOR_NONE}"
write_one " ---- but they're hard ◕︵◕"
write_one " ★ No transitions"
write_one " ★ Unicode emoji \( ゚◡゚)/"
write_one " ★ Can be dockerized"
finish_page 16
n=$(wait_key_press)
}
function page_3() {
write_one
center "BACK TO DAEMONS"
center "‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾"
breaks 5
write_one " In multitasking computer operating systems,"
write_one " a daemon (/ˈdiːmən/ or /ˈdeɪmən/) is a computer"
write_one " program that runs as a background process,"
write_one " rather than being under the direct control of"
write_one " an interactive user."
breaks 3
printf "${BLUE}"
center_one "http://en.wikipedia.org/wiki/Daemon_(computing)"
printf "$COLOR_NONE"
finish_page 18
n=$(wait_key_press)
}
function page_4() {
write_one
center "BACK TO DAEMONS"
center "‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾"
breaks 3
write_one " Daemon lifecycle"
write_one ""
write_one " PARENT PROCESS"
write_one " |"
write_one " (dissociate from TTY)"
write_one " |"
write_one " |"
write_one " +---- FORK (continues running in detached mode)"
write_one " |"
write_one " |"
write_one " (parent exits)"
breaks 1
finish_page 19
n=$(wait_key_press)
}
function page_4a() {
write_one
center "WHY BASH? (yಠ,ಠ)y"
center "‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾"
breaks 3
write_one " ★ We had a problem to solve: Make the most recent locations data"
write_one " always available on the filesystem for apps to consume"
write_one " 1. Check if a new locations data package is available"
write_one " 2. Download and unpack the new package"
write_one " 3. Repeat"
write_one
write_one " ★ We have to provide the locations data to a huge number of REA apps"
write_one " which are deployed to many different environments"
finish_page 15
n=$(wait_key_press)
}
function page_4b() {
write_one
center "WHY BASH? (yಠ,ಠ)y"
center "‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾"
breaks 3
write_one " ★ Minimum set of dependencies (Only standard Linux packages)"
write_one " ★ Rock solid technology (Bash + Curl + Tar + Openssl)"
write_one " ★ No compilation, language runtime, package managers, libraries"
write_one " ★ Will run everywhere: Cloud, Data Centre (even on Lenny), Docker"
write_one
write_one " ★ Not recommended for anything more complex"
finish_page 13
n=$(wait_key_press)
}
function page_5() {
write_one
center "DETACH IN BASH"
center "‾‾‾‾‾‾‾‾‾‾‾‾‾‾"
breaks 3
write_one "$ cat run-detach.sh"
write_one ""
write_one "nohup \\ # detach from TTY"
write_one " run.sh \\ # the main script (daemon)"
write_one " 0<&- \\ # close STDIN"
write_one " 2>err.log \\ # redirect STDERR"
write_one " >app.log \\ # redirect STDOUT"
write_one " & # run in a subshell (fork)"
write_one
write_one "echo \$! > app.pid # store the PID of the main script"
write_one
write_one "exit 0 # the parent script exits here"
finish_page 19
n=$(wait_key_press)
}
function page_6() {
write_one
center "KILLING THE DAEMON"
center "‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾"
breaks 3
write_one " # /etc/init.d/my_daemon stop"
write_one " sends SIGTERM signal to our main script"
write_one
write_one " it's the same as killing the process manually:"
write_one " \$ ps ax"
write_one " 3 s007 S 0:04.13 ./run.sh"
write_one
write_one " \$ kill 3"
write_one
write_one " Will our script cleanly exit?"
finish_page 17
n=$(wait_key_press)
}
function page_7() {
write_one
center "KILLING THE DAEMON"
center "‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾"
breaks 2
write_one " \$ cat run.sh"
write_one " #!/bin/bash"
write_one " while true; do"
write_one " echo still alive"
write_one " long_running_task"
write_one " done"
write_one
write_one " \$ /etc/init.d/my_daemon stop"
write_one
write_one " \$ ps ax"
write_one " 3 s007 S 0:04.13 long_running_task"
write_one
write_one " ★ The TERM signal is only sent to the main script"
write_one " ★ All child processes will continue running"
finish_page 20
n=$(wait_key_press)
}
function page_8() {
write_one
center "KILLING THE DAEMON AND ALL CHILD PROCESSES"
center "‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾"
breaks 2
write_one " \$ cat run.sh"
write_one " #!/bin/bash"
write_one " trap shutdown SIGTERM"
write_one
write_one " function shutdown() {"
write_one " pgid=\$(ps -o pgid= \$\$ | grep -o [0-9]*) # Get our process group id"
write_one " setsid kill -- -\$pgid # Kill all processes from the process group"
write_one " # \`setdid\` ensures that the kill will be"
write_one " # executed by the process group leaders"
write_one " exit 0"
write_one " }"
write_one
write_one " ★ All Bash child processes belong to the same process group"
write_one " ★ It is possible to kill all processes with a given process group id"
finish_page 22
n=$(wait_key_press)
}
function page_9() {
write_one
center "SENDING SIGINT TO THE DAEMON"
center "‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾"
breaks 3
write_one " $ cat run.sh"
write_one " #!/bin/bash"
write_one " while true; do"
write_one " echo still alive"
write_one " sleep 3600"
write_one " done"
write_one
write_one " $ kill -INT <pid> # it's like Ctrl+C"
write_one
write_one " ★ Bash doesn't process SIGINT during sleep"
write_one " ★ the daemon will still be running for about 1 hour"
finish_page 18
n=$(wait_key_press)
}
function page_10() {
write_one
center "SENDING SIGINT TO THE DAEMON"
center "‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾"
breaks 3
write_one " $ cat run.sh"
write_one " #!/bin/bash"
write_one
write_one " while true; do"
write_one " echo still alive"
write_one " sleep 3600 & # execute sleep in a subprocess"
write_one " wait \$! # wait for the subprocess to finish"
write_one " done"
finish_page 15
n=$(wait_key_press)
}
function page_11() {
write_one
center "LOGGING FROM THE DAEMON"
center "‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾"
breaks 1
write_one " $ cat run.sh"
write_one " #!/bin/bash"
write_one
write_one " function log() {"
write_one ' echo -e "[$(date +"%d/%b/%Y:%H:%M:%S %z")]\t$(hostname -f)\t$*"'
write_one " }"
write_one ' log "hello"'
write_one
write_one " $ cat application.log"
write_one ' [05/May/2015:00:09:54 +1000] VIC009235M.lan hello'
write_one
write_one
write_one " ★ Use standard format (i.e. Apache)"
write_one " ★ Include timestamp (UTC or with TZ info)"
finish_page 19
n=$(wait_key_press)
}
function page_last() {
write ""
breaks 8
center '¯\\_(ツ)_/¯'
breaks 4
center 'THE END'
breaks 3
finish_page 19
n=$(wait_key_press)
}
page_1
page_2
page_1a
page_3
page_4
page_4a
page_4b
page_5
page_6
page_7
page_8
page_9
page_10
page_11
page_last
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment