FISHKISSFISHKIS SFISHKISSFISHKISSFISH F ISHK ISSFISHKISSFISHKISS FI SHKISS FISHKISSFISHKISSFISS FIS HKISSFISHKISSFISHKISSFISHKISSFISH KISS FISHKISSFISHKISSFISHKISSFISHKISS FISHK SSFISHKISSFISHKISSFISHKISSFISHKISSF ISHKISSFISHKISSFISHKISSFISHKISSF ISHKI SSFISHKISSFISHKISSFISHKISSFISHKIS SFIS HKISSFISHKISSFISHKISSFISHKISS FIS HKISSFISHKISSFISHKISSFISHK IS SFISHKISSFISHKISSFISH K ISSFISHKISSFISHK
$ doas installboot sd0 # Update the bootloader (not for every upgrade required) $ doas sysupgrade # Update all binaries (including Kernel)
$ doas sysmerge # Update system configuration files $ doas pkg_add -u # Update all packages $ doas reboot # Just in case, reboot one more time
..--""""----.. .-" ..--""""--.j-. .-" .-" .--.""--.. .-" .-" ..--"-. \/ ; .-" .-"_.--..--"" ..--' "-. : .' .' / `. \..--"" __ _ \ ; :.__.-" \ / .' ( )"-. Y ; ;: ( ) ( ). \ .': /:: : \ \ .'.-"\._ _.-" ; ; ( ) .-. ( ) \ " `.""" .j" : : \ ; ; \ bug /"""""/ ; ( ) "" :.( ) \ /\ / : \ \`.: _ \ : `. / ; `( ) (\/ :" \ \ \ `. : "-.(_)_.' t-' ; \ `. ; ..--": `. `. : ..--"" : `. "-. ; ..--"" ; `. "-.:_..--"" ..--" `. : ..--"" "-. : ..--"" "-.;_..--""
'\ '\ '\ . . |>18>> \ \ \ . ' . | O>> O>> O>> . 'o | \ .\. .. .\. .. . | /\ . /\ . /\ . . | / / . / / .'. / / .' . | jgs^^^^^^^`^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Art by Joan Stark, mod. by Paul Buetow
#!/usr/bin/env bash log () { local -r level="$1"; shift local -r message="$1"; shift local -i pid="$$" local -r callee=${FUNCNAME[1]} local -r stamp=$(date +%Y%m%d-%H%M%S) echo "$level|$stamp|$pid|$callee|$message" >&2 } at_home_friday_evening () { log INFO 'One Peperoni Pizza, please' } at_home_friday_evening
❯ ./logexample.sh INFO|20231210-082732|123002|at_home_friday_evening|One Peperoni Pizza, please
#!/usr/bin/env bash outer() { inner() { echo 'Intel inside!' } inner } inner outer inner
❯ ./inner.sh /tmp/inner.sh: line 10: inner: command not found Intel inside! Intel inside!
#!/usr/bin/env bash outer1() { inner() { echo 'Intel inside!' } inner } outer2() { inner() { echo 'Wintel inside!' } inner } outer1 inner outer2 inner
❯ ./inner2.sh Intel inside! Intel inside! Wintel inside! Wintel inside!
#!/usr/bin/env bash some_expensive_operations() { echo "Doing expensive operations with '$1' from pid $$" } for i in {0..9}; do echo $i; done \ | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
❯ ./xargs.sh bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found bash: line 1: some_expensive_operations: command not found
#!/usr/bin/env bash some_expensive_operations() { echo "Doing expensive operations with '$1' from pid $$" } export -f some_expensive_operations for i in {0..9}; do echo $i; done \ | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
❯ ./xargs.sh Doing expensive operations with '0' from pid 132831 Doing expensive operations with '1' from pid 132832 Doing expensive operations with '2' from pid 132833 Doing expensive operations with '3' from pid 132834 Doing expensive operations with '4' from pid 132835 Doing expensive operations with '5' from pid 132836 Doing expensive operations with '6' from pid 132837 Doing expensive operations with '7' from pid 132838 Doing expensive operations with '8' from pid 132839 Doing expensive operations with '9' from pid 132840
#!/usr/bin/env bash some_other_function() { echo "$1" } some_expensive_operations() { some_other_function "Doing expensive operations with '$1' from pid $$" } export -f some_expensive_operations for i in {0..9}; do echo $i; done \ | xargs -P10 -I{} bash -c 'some_expensive_operations "{}"'
#!/usr/bin/env bash foo() { local foo=bar # Declare local/dynamic variable bar echo "$foo" } bar() { echo "$foo" foo=baz } foo=foo # Declare global variable foo # Call function foo echo "$foo"
❯ ./dynamic.sh bar baz foo
#!/usr/bin/env bash declare -r foo=foo declare -r bar=bar if [ "$foo" = foo ]; then if [ "$bar" = bar ]; then echo ok1 fi fi if [ "$foo" = foo ] && [ "$bar" == bar ]; then echo ok2a fi [ "$foo" = foo ] && [ "$bar" == bar ] && echo ok2b if [[ "$foo" = foo && "$bar" == bar ]]; then echo ok3a fi [[ "$foo" = foo && "$bar" == bar ]] && echo ok3b if test "$foo" = foo && test "$bar" = bar; then echo ok4a fi test "$foo" = foo && test "$bar" = bar && echo ok4b
❯ ./if.sh ok1 ok2a ok2b ok3a ok3b ok4a ok4b
#!/usr/bin/env bash # Single line comment # These are two single line # comments one after another : <<COMMENT This is another way a multi line comment could be written! COMMENT
#!/usr/bin/env bash echo foo echo echo baz >> $0 echo bar
❯ ./if.sh foo bar baz ❯ cat if.sh #!/usr/bin/env bash echo foo echo echo baz >> $0 echo bar echo baz
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣾⣷⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⣾⠿⠿⠿⠶⠾⠿⠿⣿⣿⣿⣿⣿⣿⠿⠿⠶⠶⠿⠿⠿⣷⠀⠀⠀⠀ ⠀⠀⠀⣸⢿⣆⠀⠀⠀⠀⠀⠀⠀⠙⢿⡿⠉⠀⠀⠀⠀⠀⠀⠀⣸⣿⡆⠀⠀⠀ ⠀⠀⢠⡟⠀⢻⣆⠀⠀⠀⠀⠀⠀⠀⣾⣧⠀⠀⠀⠀⠀⠀⠀⣰⡟⠀⢻⡄⠀⠀ ⠀⢀⣾⠃⠀⠀⢿⡄⠀⠀⠀⠀⠀⢠⣿⣿⡀⠀⠀⠀⠀⠀⢠⡿⠀⠀⠘⣷⡀⠀ ⠀⣼⣏⣀⣀⣀⣈⣿⡀⠀⠀⠀⠀⣸⣿⣿⡇⠀⠀⠀⠀⢀⣿⣃⣀⣀⣀⣸⣧⠀ ⠀⢻⣿⣿⣿⣿⣿⣿⠃⠀⠀⠀⠀⣿⣿⣿⣿⠀⠀⠀⠀⠈⢿⣿⣿⣿⣿⣿⡿⠀ ⠀⠀⠉⠛⠛⠛⠋⠁⠀⠀⠀⠀⢸⣿⣿⣿⣿⡆⠀⠀⠀⠀⠈⠙⠛⠛⠛⠉⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠴⠶⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠶⠦⠀⠀
,.......... .........., ,..,' '.' ',.., ,' ,' : ', ', ,' ,' : ', ', ,' ,' : ', ', ,' ,'............., : ,.............', ', ,' '............ '.' ............' ', '''''''''''''''''';''';'''''''''''''''''' '''
___ .---------.._ ______!fsc!_....-' .g8888888p. '-------....._ .' // .g8: :8p..---....___ \'. | foo.zone // () d88: :88b|==========! !| | // 888: :888|==========| !| |___ \\_______'T88888888888P''----------'//| | \ """"""""""""""""""""""""""""""""""/ | | !...._____ .="""=. .[] ____...! | | / ! .g$p. ! .[] : | | ! : $$$$$ : .[] : | | !irregular.ninja ! 'T$P' ! .[] '.| | \__ "=._.=" .() __ | |.--' '----._______________________.----' '--.| '._____________________________________________.'
% sudo dnf install -y ImageMagick make git
% git clone https://codeberg.org/snonux/photoalbum Cloning into 'photoalbum'... remote: Enumerating objects: 1624, done. remote: Total 1624 (delta 0), reused 0 (delta 0), pack-reused 1624 Receiving objects: 100% (1624/1624), 193.36 KiB | 1.49 MiB/s, done. Resolving deltas: 100% (1227/1227), done. % cd photoalbum /home/paul/photoalbum % make cut -d' ' -f2 changelog | head -n 1 | sed 's/(//;s/)//' > .version test ! -d ./bin && mkdir ./bin || exit 0 sed "s/PHOTOALBUMVERSION/$(cat .version)/" src/photoalbum.sh > ./bin/photoalbum chmod 0755 ./bin/photoalbum % sudo make install test ! -d /usr/bin && mkdir -p /usr/bin || exit 0 cp ./bin/* /usr/bin test ! -d /usr/share/photoalbum/templates && mkdir -p /usr/share/photoalbum/templates || exit 0 cp -R ./share/templates /usr/share/photoalbum/ test ! -d /etc/default && mkdir -p /etc/default || exit 0 cp ./src/photoalbum.default.conf /etc/default/photoalbum
% photoalbum version This is Photoalbum Version 0.5.1
% mkdir irregular.ninja % cd irregular.ninja % # cp -Rpv ~/Photos/your-photos ./incoming
photoalbum clean|generate|version [rcfile] photoalbum photoalbum makemake
% photoalbum makemake You may now customize ./photoalbumrc and run make % cat Makefile all: photoalbum generate photoalbumrc clean: photoalbum clean photoalbumrc % cat photoalbumrc # The title of the photoalbum TITLE='A simple Photoalbum' # Thumbnail height geometry THUMBHEIGHT=300 # Normal geometry height (when viewing photo). Uncomment, to keep original size. HEIGHT=1200 # Max previews per page. MAXPREVIEWS=40 # Randomly shuffle all previews. # SHUFFLE=yes # Diverse directories, need to be full paths, not relative! INCOMING_DIR=$(pwd)/incoming DIST_DIR=$(pwd)/dist TEMPLATE_DIR=/usr/share/photoalbum/templates/default #TEMPLATE_DIR=/usr/share/photoalbum/templates/minimal # Includes a .tar of the incoming dir in the dist, can be yes or no TARBALL_INCLUDE=yes TARBALL_SUFFIX=.tar TAR_OPTS='-c' # Some debugging options #set -e #set -x
--- photoalbumrc 2023-10-29 21:42:00.894202045 +0200 +++ photoalbumrc.new 2023-06-04 10:40:08.030994440 +0300 @@ -1,23 +1,24 @@ # The title of the photoalbum -TITLE='A simple Photoalbum' +TITLE='Irregular.Ninja' # Thumbnail height geometry -THUMBHEIGHT=300 +THUMBHEIGHT=400 # Normal geometry height (when viewing photo). Uncomment, to keep original size. -HEIGHT=1200 +HEIGHT=1800 # Max previews per page. MAXPREVIEWS=40 -# Randomly shuffle all previews. -# SHUFFLE=yes +# Randomly shuffle +SHUFFLE=yes # Diverse directories, need to be full paths, not relative! -INCOMING_DIR=$(pwd)/incoming +INCOMING_DIR=~/Nextcloud/Photos/irregular.ninja DIST_DIR=$(pwd)/dist TEMPLATE_DIR=/usr/share/photoalbum/templates/default #TEMPLATE_DIR=/usr/share/photoalbum/templates/minimal # Includes a .tar of the incoming dir in the dist, can be yes or no -TARBALL_INCLUDE=yes +TARBALL_INCLUDE=no TARBALL_SUFFIX=.tar TAR_OPTS='-c'
% make photoalbum generate photoalbumrc Processing 1055079_cool-water-wallpapers-hd-hd-desktop-wal.jpg to /home/paul/irregular.ninja/dist/photos/1055079_cool-water-wallpapers-hd-hd-desktop-wal.jpg Processing 11271242324.jpg to /home/paul/irregular.ninja/dist/photos/11271242324.jpg Processing 11271306683.jpg to /home/paul/irregular.ninja/dist/photos/11271306683.jpg Processing 13950707932.jpg to /home/paul/irregular.ninja/dist/photos/13950707932.jpg Processing 14077406487.jpg to /home/paul/irregular.ninja/dist/photos/14077406487.jpg Processing 14859380100.jpg to /home/paul/irregular.ninja/dist/photos/14859380100.jpg Processing 14869239578.jpg to /home/paul/irregular.ninja/dist/photos/14869239578.jpg Processing 14879132910.jpg to /home/paul/irregular.ninja/dist/photos/14879132910.jpg . . . Generating /home/paul/irregular.ninja/dist/html/7-4.html Creating thumb /home/paul/irregular.ninja/dist/thumbs/20211130_091051.jpg Creating blur /home/paul/irregular.ninja/dist/blurs/20211130_091051.jpg Generating /home/paul/irregular.ninja/dist/html/page-7.html Generating /home/paul/irregular.ninja/dist/html/7-5.html Generating /home/paul/irregular.ninja/dist/html/7-5.html Generating /home/paul/irregular.ninja/dist/html/7-5.html Creating thumb /home/paul/irregular.ninja/dist/thumbs/DSCF0188.JPG Creating blur /home/paul/irregular.ninja/dist/blurs/DSCF0188.JPG Generating /home/paul/irregular.ninja/dist/html/page-7.html Generating /home/paul/irregular.ninja/dist/html/7-6.html Generating /home/paul/irregular.ninja/dist/html/7-6.html Generating /home/paul/irregular.ninja/dist/html/7-6.html Creating thumb /home/paul/irregular.ninja/dist/thumbs/P3500897-01.jpg Creating blur /home/paul/irregular.ninja/dist/blurs/P3500897-01.jpg . . . Generating /home/paul/irregular.ninja/dist/html/8-0.html Generating /home/paul/irregular.ninja/dist/html/8-41.html Generating /home/paul/irregular.ninja/dist/html/9-0.html Generating /home/paul/irregular.ninja/dist/html/9-41.html Generating /home/paul/irregular.ninja/dist/html/index.html Generating /home/paul/irregular.ninja/dist/.//index.html
% ls ./dist blurs html index.html photos thumbs
% rsync --delete -av ./dist/. admin@blowfish.buetow.org:/var/www/htdocs/irregular.ninja/
,_---~~~~~----._ _,,_,*^____ _____``*g*\"*, ____ _____ _ _ / __/ /' ^. / \ ^@q f | _ \_ _|_ _(_) | @f | ((@| |@)) l 0 _/ | | | || |/ _` | | | \`/ \~____ / __ \_____/ \ | |_| || | (_| | | | | _l__l_ I |____/ |_|\__,_|_|_| } [______] I ] | | | | ] ~ ~ | | Let's tail those logs! | | |
% dtail --servers serverlist.txt --grep INFO --files "/var/log/dserver/*.log"
% dtail --servers serverlist.txt --grep INFO "/var/log/dserver/*.log"
% dtail --servers serverlist.txt \ --files '/var/log/dserver/*.log' \ --query 'from STATS select sum($goroutines),sum($cgocalls), last($time),max(lifetimeConnections)'
% dtail --servers serverlist.txt \ --files '/var/log/dserver/*.log' \ 'from STATS select sum($goroutines),sum($cgocalls), last($time),max(lifetimeConnections)'
% dtail --servers serverlist.txt \ --files '/var/log/dserver/*.log' \ --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg, lifetimeConnections group by $hostname order by max($cgocalls)'
% dtail --servers serverlist.txt \ --files '/var/log/dserver/*.log' \ --query 'from STATS select ... outfile append result.csv'
% dcat --servers serverlist.txt --files /etc/hostname
% dcat --servers serverlist.txt /etc/hostname
% dgrep --servers server1.example.org:2223 \ --files /etc/passwd \ --regex nologin
% dmap --servers serverlist.txt \ --files '/var/log/dserver/*.log' \ --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg, lifetimeConnections group by $hostname order by max($cgocalls)'
% dmap --files /var/log/dserver/dserver.log --query 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg, lifetimeConnections group by $hostname order by max($cgocalls)'
% dmap 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg, lifetimeConnections group by $hostname order by max($cgocalls)' \ /var/log/dsever/dserver.log
% cat /var/log/dserver/dserver.log | \ dmap 'from STATS select $hostname,max($goroutines),max($cgocalls),$loadavg, lifetimeConnections group by $hostname order by max($cgocalls)'
% cat example.csv name,lastname,age,profession Michael,Jordan,40,Basketball player Michael,Jackson,100,Singer Albert,Einstein,200,Physician % dmap --query 'select lastname,name where age > 40 logformat csv outfile result.csv' example.csv % cat result.csv lastname,name Jackson,Michael Einstein,Albert
% dtail /var/log/dserver/dserver.log
% dtail --logLevel trace /var/log/dserver/dserver.log
% dcat /etc/passwd
% dcat --plain /etc/passwd > /etc/test # Should show no differences. diff /etc/test /etc/passwd
% dgrep --regex ERROR --files /var/log/dserver/dsever.log
% dgrep --before 10 --after 10 --max 10 --grep ERROR /var/log/dserver/dsever.log
▓▓▓▓░░ DC on fire: ▓▓ ▓▓ ▓▓ ░░ ░░ ▓▓▓▓ ██ ░░ ▓▓▓▓ ▓▓ ▓▓░░░░ ░░ ▓▓▓▓ ▓▓░░ ▓▓▓▓ ░░░░ ▓▓▓▓▓▓ ▓▓ ▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓ ▓▓░░ ▓▓▒▒▒▒▓▓▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓▓▓ ▓▓▒▒▒▒▓▓▓▓ ▓▓▓▓ ██▓▓ ▓▓▒▒░░▒▒▓▓ ▓▓██ ▓▓▓▓▓▓ ▓▓▒▒▓▓ ▓▓▒▒░░▒▒▓▓ ██▓▓▓▓ ▓▓▓▓██ ▓▓▒▒░░░░▒▒▓▓ ▓▓▓▓ ▓▓▒▒▒▒▓▓ ▓▓▒▒░░▒▒▓▓██▓▓ ▓▓▒▒░░░░▒▒▓▓ ▓▓▒▒▒▒▓▓ ▓▓▒▒▒▒▓▓▓▓▒▒░░▒▒▓▓▓▓▓▓▒▒▒▒▓▓ ▓▓▓▓░░▒▒▓▓ ▓▓▒▒░░▒▒▓▓▒▒▒▒▓▓ ▓▓▒▒░░▒▒▓▓▓▓▓▓▓▓░░▒▒▓▓ ▒▒░░▒▒▓▓▓▓▒▒░░▒▒▓▓▓▓▒▒░░▒▒▓▓ ▓▓▒▒░░▒▒▓▓ ▓▓░░░░▒▒▒▒░░░░▒▒██████▒▒░░▒▒██▓▓▓▓▒▒░░▒▒▓▓██ ░░░░▒▒▓▓▒▒░░▒▒▓▓▓▓▓▓▒▒░░▒▒▓▓██▒▒░░░░▒▒▓▓ ▓▓▒▒░░▒▒▓▓▒▒▒▒░░▒▒▓▓▓▓▒▒░░▒▒▓▓▓▓▓▓▒▒░░░░▒▒▓▓▓▓ ░░░░▒▒▓▓▒▒░░░░▓▓██▒▒░░░░▒▒▓▓██▒▒░░░░▒▒██▓▓▓▓▒▒░░▒▒▓▓▓▓▒▒░░░░▒▒▓▓▒▒░░░░██▓▓▓▓▒▒░░░░▒▒████ ▒▒░░▒▒▓▓▓▓░░░░▒▒▓▓▒▒▒▒░░░░▒▒▓▓▓▓▒▒░░░░▒▒▓▓▓▓▒▒░░░░▒▒▓▓▒▒░░▒▒▓▓▓▓▓▓░░░░▒▒▓▓▓▓▓▓▒▒░░░░▒▒▓▓ ▒▒░░▒▒▓▓▒▒▒▒░░▒▒██▒▒▒▒░░▒▒▒▒██▒▒▒▒░░░░░░▒▒▓▓▒▒░░░░▒▒▒▒░░░░▒▒████▒▒▒▒░░▒▒██▓▓▒▒▒▒░░░░░░▒▒ ░░░░░░▒▒░░░░░░░░▒▒▒▒▒▒░░░░▒▒▒▒▒▒░░░░░░░░▒▒▒▒░░░░░░▒▒▒▒░░░░░░▒▒▒▒░░░░░░░░▒▒▒▒▒▒░░░░░░░░▒▒ ░░░░░░░░░░▒▒░░░░░░░░░░░░░░░░░░░░░░░░▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒░░░░░░░░░░░░░░░░░░
-=[ typewriters ]=- 1/98 .-------. .-------. _|~~ ~~ |_ _|~~ ~~ |_ .-------. =(_|_______|_) =(_|_______|_)= _|~~ ~~ |_ |:::::::::| |:::::::::| =(_|_______|_) |:::::::[]| |:::::::[]| |:::::::::| |o=======.| |o=======.| |:::::::[]| `"""""""""` jgs `"""""""""` |o=======.| mod. by Paul Buetow `"""""""""`
```bash if [ -n "$foo" ]; then echo "$foo" fi ```
if [ -n "$foo" ]; then echo "$foo" fi
declare -xr MASTODON_URI='https://fosstodon.org/@snonux'
=> https://fosstodon.org/@snonux Me at Mastodon
<a href='https://fosstodon.org/@snonux' rel='me'>Me at Mastodon</a>
,.......... .........., ,..,' '.' ',.., ,' ,' : ', ', ,' ,' : ', ', ,' ,' : ', ', ,' ,'............., : ,.............', ', ,' '............ '.' ............' ', '''''''''''''''''';''';'''''''''''''''''' '''
_____________________________ ____________________________ / \ / \ | _______________________ || ______________________ | | / \ || / \ | | | # Alerts with status c| || | # Unhandled alerts: | | | | hanged: | || | | | | | | || | CRITICAL: Check Pizza| | | | OK->CRITICAL: Check Pi| || | : Late delivery | | | | zza: Late delivery | || | | | | | | || | WARNING: Check Thirst| | | | | || | : OutofKombuchaExcept| | | \_______________________/ || \______________________/ | | /|\ GOGIOS MONITOR 1 _ || /|\ GOGIOS MONITOR 2 _ | \_____________________________/ \____________________________/ !_________________________! !________________________! ------------------------------------------------ ASCII art was modified by Paul Buetow The original can be found at https://asciiart.website/index.php?art=objects/computers
Subject: GOGIOS Report [C:2 W:0 U:0 OK:51] This is the recent Gogios report! # Alerts with status changed: OK->CRITICAL: Check ICMP4 vulcan.buetow.org: Check command timed out OK->CRITICAL: Check ICMP6 vulcan.buetow.org: Check command timed out # Unhandled alerts: CRITICAL: Check ICMP4 vulcan.buetow.org: Check command timed out CRITICAL: Check ICMP6 vulcan.buetow.org: Check command timed out Have a nice day!
git clone https://codeberg.org/snonux/gogios.git cd gogios go build -o gogios cmd/gogios/main.go doas cp gogios /usr/local/bin/gogios doas chmod 755 /usr/local/bin/gogios
export GOOS=openbsd export GOARCH=amd64 go build -o gogios cmd/gogios/main.go
doas adduser -group _gogios -batch _gogios doas usermod -d /var/run/gogios _gogios doas mkdir -p /var/run/gogios doas chown _gogios:_gogios /var/run/gogios doas chmod 750 /var/run/gogios
doas pkg_add monitoring-plugins doas pkg_add nrpe # If you want to execute checks remotely via NRPE.
echo 'This is a test email from OpenBSD.' | mail -s 'Test Email' your-email@example.com
{ "EmailTo": "paul@dev.buetow.org", "EmailFrom": "gogios@buetow.org", "CheckTimeoutS": 10, "CheckConcurrency": 2, "StateDir": "/var/run/gogios", "Checks": { "Check ICMP4 www.foo.zone": { "Plugin": "/usr/local/libexec/nagios/check_ping", "Args": [ "-H", "www.foo.zone", "-4", "-w", "50,10%", "-c", "100,15%" ], "Retries": 3, "RetryInterval": 10 }, "Check ICMP6 www.foo.zone": { "Plugin": "/usr/local/libexec/nagios/check_ping", "Args": [ "-H", "www.foo.zone", "-6", "-w", "50,10%", "-c", "100,15%" ], "Retries": 3, "RetryInterval": 10 }, "www.foo.zone HTTP IPv4": { "Plugin": "/usr/local/libexec/nagios/check_http", "Args": ["www.foo.zone", "-4"], "DependsOn": ["Check ICMP4 www.foo.zone"] }, "www.foo.zone HTTP IPv6": { "Plugin": "/usr/local/libexec/nagios/check_http", "Args": ["www.foo.zone", "-6"], "DependsOn": ["Check ICMP6 www.foo.zone"] } "Check NRPE Disk Usage foo.zone": { "Plugin": "/usr/local/libexec/nagios/check_nrpe", "Args": ["-H", "foo.zone", "-c", "check_disk", "-p", "5666", "-4"] } } }
doas -u _gogios /usr/local/bin/gogios -cfg /etc/gogios.json
*/5 8-22 * * * /usr/local/bin/gogios -cfg /etc/gogios.json 0 7 * * * /usr/local/bin/gogios -renotify -cfg /etc/gogios.json
,.......... .........., ,..,' '.' ',.., ,' ,' : ', ', ,' ,' : ', ', ,' ,' : ', ', ,' ,'............., : ,.............', ', ,' '............ '.' ............' ', '''''''''''''''''';''';'''''''''''''''''' '''
+-----+-----------------+-----------------------------+ | Pos | Host | Lifespan | +-----+-----------------+-----------------------------+ | 1. | dionysus | 8 years, 6 months, 17 days | | 2. | uranus | 7 years, 2 months, 16 days | | 3. | alphacentauri | 6 years, 9 months, 13 days | | 4. | *vulcan | 4 years, 5 months, 6 days | | 5. | sun | 3 years, 10 months, 2 days | | 6. | uugrn | 3 years, 5 months, 5 days | | 7. | deltavega | 3 years, 1 months, 21 days | | 8. | pluto | 2 years, 10 months, 30 days | | 9. | tauceti | 2 years, 3 months, 22 days | | 10. | callisto | 2 years, 3 months, 13 days | +-----+-----------------+-----------------------------+
$ raku guprecords.raku --stats=dir=$HOME/git/uprecords/stats --all
Top 20 Uptime's by Host +-----+-----------------+-----------------------------+ | Pos | Host | Uptime | +-----+-----------------+-----------------------------+ | 1. | *vulcan | 4 years, 5 months, 6 days | | 2. | uranus | 3 years, 11 months, 21 days | | 3. | sun | 3 years, 9 months, 26 days | | 4. | uugrn | 3 years, 5 months, 5 days | | 5. | deltavega | 3 years, 1 months, 21 days | | 6. | pluto | 2 years, 10 months, 29 days | | 7. | tauceti | 2 years, 3 months, 19 days | | 8. | tauceti-f | 1 years, 9 months, 18 days | | 9. | *ultramega15289 | 1 years, 8 months, 17 days | | 10. | *earth | 1 years, 5 months, 22 days | | 11. | *blowfish | 1 years, 4 months, 20 days | | 12. | ultramega8477 | 1 years, 3 months, 25 days | | 13. | host0 | 1 years, 3 months, 9 days | | 14. | tauceti-e | 1 years, 2 months, 20 days | | 15. | makemake | 1 years, 1 months, 6 days | | 16. | callisto | 0 years, 10 months, 31 days | | 17. | alphacentauri | 0 years, 10 months, 28 days | | 18. | london | 0 years, 9 months, 16 days | | 19. | twofish | 0 years, 8 months, 31 days | | 20. | *fishfinger | 0 years, 8 months, 17 days | +-----+-----------------+-----------------------------+
# Uptime | System Boot up ----------------------------+--------------------------------------------------- 1 545 days, 17:58:15 | Linux 3.10.0-1160.15.2.e Sun Jul 25 19:32:25 2021 2 279 days, 10:12:14 | Linux 3.10.0-957.21.3.el Sun Jun 30 12:43:41 2019 3 161 days, 06:08:43 | Linux 3.10.0-1160.15.2.e Sun Feb 14 11:05:38 2021 4 107 days, 01:26:35 | Linux 3.10.0-957.1.3.el7 Thu Dec 20 09:29:13 2018 5 96 days, 21:13:49 | Linux 3.10.0-1127.13.1.e Sat Jul 25 17:56:22 2020 -> 6 89 days, 23:05:32 | Linux 3.10.0-1160.81.1.e Sun Jan 22 12:39:36 2023 7 63 days, 18:30:45 | Linux 3.10.0-957.10.1.el Sat Apr 27 18:12:43 2019 8 63 days, 06:53:33 | Linux 3.10.0-1127.8.2.el Sat May 23 10:41:08 2020 9 48 days, 11:44:49 | Linux 3.10.0-1062.18.1.e Sat Apr 4 22:56:07 2020 10 42 days, 08:00:13 | Linux 3.10.0-1127.19.1.e Sat Nov 7 11:47:33 2020 11 36 days, 22:57:19 | Linux 3.10.0-1160.6.1.el Sat Dec 19 19:47:57 2020 12 21 days, 06:16:28 | Linux 3.10.0-957.10.1.el Sat Apr 6 11:56:01 2019 13 12 days, 20:11:53 | Linux 3.10.0-1160.11.1.e Mon Jan 25 18:45:27 2021 14 7 days, 21:29:18 | Linux 3.10.0-1127.13.1.e Fri Oct 30 14:18:04 2020 15 6 days, 20:07:18 | Linux 3.10.0-1160.15.2.e Sun Feb 7 14:57:35 2021 16 1 day , 21:46:41 | Linux 3.10.0-957.1.3.el7 Tue Dec 18 11:42:19 2018 17 0 days, 01:25:57 | Linux 3.10.0-957.1.3.el7 Tue Dec 18 10:16:08 2018 18 0 days, 00:42:34 | Linux 3.10.0-1160.15.2.e Sun Jul 25 18:49:38 2021 19 0 days, 00:08:32 | Linux 3.10.0-1160.81.1.e Sun Jan 22 12:30:52 2023 ----------------------------+--------------------------------------------------- 1up in 6 days, 22:08:18 | at Sat Apr 29 10:53:25 2023 no1 in 455 days, 18:52:44 | at Sun Jul 21 07:37:51 2024 up 1586 days, 00:20:28 | since Tue Dec 18 10:16:08 2018 down 0 days, 01:08:32 | since Tue Dec 18 10:16:08 2018 %up 99.997 | since Tue Dec 18 10:16:08 2018
,_---~~~~~----._ _,,_,*^____ _____``*g*\"*, / __/ /' ^. / \ ^@q f [ @f | @)) | | @)) l 0 _/ \`/ \~____ / __ \_____/ \ | _l__l_ I } [______] I ] | | | | ] ~ ~ | | | | |
package ds import ( "golang.org/x/exp/constraints" ) type Integer interface { constraints.Integer } type Number interface { constraints.Integer | constraints.Float }
package ds import ( "fmt" "math/rand" "strings" ) type ArrayList[V Number] []V func NewArrayList[V Number](l int) ArrayList[V] { return make(ArrayList[V], l) }
func NewRandomArrayList[V Number](l, max int) ArrayList[V] { a := make(ArrayList[V], l) for i := 0; i < l; i++ { if max > 0 { a[i] = V(rand.Intn(max)) continue } a[i] = V(rand.Int()) } return a } func NewAscendingArrayList[V Number](l int) ArrayList[V] { a := make(ArrayList[V], l) for i := 0; i < l; i++ { a[i] = V(i) } return a } func NewDescendingArrayList[V Number](l int) ArrayList[V] { a := make(ArrayList[V], l) j := l - 1 for i := 0; i < l; i++ { a[i] = V(j) j-- } return a }
func (a ArrayList[V]) FirstN(n int) string { var sb strings.Builder j := n l := len(a) if j > l { j = l } for i := 0; i < j; i++ { fmt.Fprintf(&sb, "%v ", a[i]) } if j < l { fmt.Fprintf(&sb, "... ") } return sb.String() }
func (a ArrayList[V]) Sorted() bool { for i := len(a) - 1; i > 0; i-- { if a[i] < a[i-1] { return false } } return true }
func (a ArrayList[V]) Swap(i, j int) { aux := a[i] a[i] = a[j] a[j] = aux }
package sort import ( "codeberg.org/snonux/algorithms/ds" "sync" "time" ) func Sleep[V ds.Integer](a ds.ArrayList[V]) ds.ArrayList[V] { sorted := ds.NewArrayList[V](len(a)) numCh := make(chan V) var wg sync.WaitGroup wg.Add(len(a)) go func() { wg.Wait() close(numCh) }() for _, num := range a { go func(num V) { defer wg.Done() time.Sleep(time.Duration(num) * time.Second) numCh <- num }(num) } for num := range numCh { sorted = append(sorted, num) } return sorted }
package sort import ( "fmt" "testing" "codeberg.org/snonux/algorithms/ds" ) func TestSleepSort(t *testing.T) { a := ds.NewRandomArrayList[int](10, 10) a = Sleep(a) if !a.Sorted() { t.Errorf("Array not sorted: %v", a) } }
❯ go test ./sort -v -run SleepSort === RUN TestSleepSort --- PASS: TestSleepSort (9.00s) PASS ok codeberg.org/snonux/algorithms/sort 9.002s
,.......... .........., ,..,' '.' ',.., ,' ,' : ', ', ,' ,' : ', ', ,' ,' : ', ', ,' ,'............., : ,.............', ', ,' '............ '.' ............' ', '''''''''''''''''';''';'''''''''''''''''' '''
-=[ typewriters ]=- 1/98 .-------. _|~~ ~~ |_ .-------. =(_|_______|_)= _|~~ ~~ |_ |:::::::::| =(_|_______|_) |:::::::[]| |:::::::::| |o=======.| |:::::::[]| jgs `"""""""""` |o=======.| mod. by Paul Buetow `"""""""""`
# Hello world << echo "> This site was generated at $(date --iso-8601=seconds) by \`Gemtexter\`" Welcome to this capsule! <<< for i in {1..10}; do echo Multiline template line $i done >>>
# Hello world > This site was generated at 2023-03-15T19:07:59+02:00 by `Gemtexter` Welcome to this capsule! Multiline template line 1 Multiline template line 2 Multiline template line 3 Multiline template line 4 Multiline template line 5 Multiline template line 6 Multiline template line 7 Multiline template line 8 Multiline template line 9 Multiline template line 10
See more entries about DTail and Golang: << template::inline::index dtail golang Blablabla...
See more entries about DTail and Golang: => ./2022-10-30-installing-dtail-on-openbsd.html 2022-10-30 Installing DTail on OpenBSD => ./2022-04-22-programming-golang.html 2022-04-22 The Golang Programming language => ./2022-03-06-the-release-of-dtail-4.0.0.html 2022-03-06 The release of DTail 4.0.0 => ./2021-04-22-dtail-the-distributed-log-tail-program.html 2021-04-22 DTail - The distributed log tail program (You are currently reading this) Blablabla...
declare -xr PRE_GENERATE_HOOK=./pre_generate_hook.sh declare -xr POST_PUBLISH_HOOK=./post_publish_hook.sh
% cat gemfeed/2023-02-26-title-here.gmi # Title here The remaining content of the Gemtext file...
% cat gemfeed/2023-02-26-title-here.gmi # Title here > Published at 2023-02-26T21:43:51+01:00 The remaining content of the Gemtext file...
,.......... .........., ,..,' '.' ',.., ,' ,' : ', ', ,' ,' : ', ', ,' ,' : ', ', ,' ,'............., : ,.............', ', ,' '............ '.' ............' ', '''''''''''''''''';''';'''''''''''''''''' '''
|\ "Music should be heard not only with the ears, but also the soul." |---|--\-----------------------|-----------------------------------------| | | |\ | |@ |\ | |---|---|--\-------------------|-------------/|----|------|--\----|------| | @| | |\ |O | 3 / | |@ | | | |---|--@|---|--\--------|------|---------/----|----|------|-------|------| | @| @| \ |O | / | | |@ @| @|. | |-----------|-----|-----|------|-----/---|---@|----|--------------|------| | @| | |O | | | | @|. | |-----------|----@|-----|------|----|---@|------------------------|------| @| | | Larry Komro @|. -@- [kom...@uwec.edu]
Art by Joan Stark _.===========================._ .'` .- - __- - - -- --__--- -. `'. __ / ,'` _|--|_________|--|_ `'. \ /'--| ; _.'\ | ' ' | /'._ ; | // | |_.-' .-'.' ___ '.'-. '-._| | (\) \"` _.-` / .-'`_ `'-. \ `-._ `"/ (\) `-' | .' .-'" "'-. '. | `-` (\) | / .'(3)(2)(1)'. \ | (\) | / / (4) .-. \ \ | (\) | | |(5) ( )'==,J | | (\) | \ \ (6) '-' (0) / / | (\) | \ '.(7)(8)(9).' / | (\) ___| '. '-.._..-' .' | (\) /.--| '-._____.-' | (\) (\) |\_ _ __ _ __ __/| (\) (\) | | (\)_._._.__(\) | | (\\\\jgs\\\) '.___________________.' '-'-'-'--'
_/ \ _(\(o / \ / _ ^^^o / ! \/ ! '!!!v' ! ! \ _' ( \____ ! . \ _!\ \===^\) Art by \ \_! / __! Gunnar Z. \! / \ <--- Emacs is a giant dragon (\_ _/ _\ ) \ ^^--^^ __-^ /(__ ^^----^^ "^--v'
" Clipboard vnoremap ,y !pbcopy<CR>ugv vnoremap ,i !pbpaste<CR> nmap ,i !wpbpaste<CR>
,_---~~~~~----._ _,,_,*^____ _____``*g*\"*, / __/ /' ^. / \ ^@q f @f | | | | 0 _/ \`/ \~__((@/ __ \__((@/ \ | _l__l_ I <--- The Go Gopher } [______] I ] | | | | ] ~ ~ | | | | | | | A ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~|~~~,--,-/ \---,-/|~~,~~~~~~~~~~~~~~~~~~~~~~~~~~~ _|\,'. /| /| `/|-. \`.' /| , `;. ,'\ A A A A _ /| `.; ,/ _ A _ / _ /| ; /\ / \ , , A / / `/| /_| | _ \ , , ,/ \ // | |/ `.\ ,- , , ,/ ,/ \/ / @| |@ / /' \ \ , > /| ,--. |\_/ \_/ / | | , ,/ \ ./' __:.. | __ __ | | | .--. , > > |-' / ` ,/| / ' \ | | | \ , | / / |<--.__,->| | | . `. > > / ( /_,' \\ ^ / \ / / `. >-- /^\ | \\___/ \ / / \__' \ \ \/ \ | `. |/ , , /`\ \ ) \ ' |/ , V \ / `-\ OpenBSD Puffy ---> `|/ ' V V \ \.' \_ '`-. V V \./'\ `|/-. \ / \ /,---`\ kat / `._____V_____V' ' '
$ doas pkg_add git go gmake
$ mkdir git $ cd git $ git clone https://github.com/mimecast/dtail $ cd dtail $ gmake
$ ./dtail --version DTail 4.1.0 Protocol 4.1 Have a lot of fun! $ file dtail dtail: ELF 64-bit LSB executable, x86-64, version 1
$ doas pkg_delete git go gmake
$ for bin in dserver dcat dgrep dmap dtail dtailhealth; do doas cp -p $bin /usr/local/bin/$bin doas chown root:wheel /usr/local/bin/$bin done
$ doas adduser -class nologin -group _dserver -batch _dserver $ doas usermod -d /var/run/dserver/ _dserver
$ cat <<'END' | doas tee /etc/rc.d/dserver #!/bin/ksh daemon="/usr/local/bin/dserver" daemon_flags="-cfg /etc/dserver/dtail.json" daemon_user="_dserver" . /etc/rc.d/rc.subr rc_reload=NO rc_pre() { install -d -o _dserver /var/log/dserver install -d -o _dserver /var/run/dserver/cache } rc_cmd $1 & END $ doas chmod 755 /etc/rc.d/dserver
desc 'Setup DTail'; task 'dtail', group => 'frontends', sub { my $restart = FALSE; file '/etc/rc.d/dserver': content => template('./etc/rc.d/dserver.tpl'), owner => 'root', group => 'wheel', mode => '755', on_change => sub { $restart = TRUE }; . . . . service 'dserver' => 'restart' if $restart; service 'dserver', ensure => 'started'; };
$ doas mkdir /etc/dserver $ curl https://raw.githubusercontent.com/mimecast/dtail/master/examples/dtail.json.examples | doas tee /etc/dserver/dtail.json
"Common": { "LogDir": "/var/log/dserver", "Logger": "Fout", "LogRotation": "Daily", "CacheDir": "cache", "SSHPort": 2222, "LogLevel": "Info" }
file '/etc/dserver', ensure => 'directory'; file '/etc/dserver/dtail.json', content => template('./etc/dserver/dtail.json.tpl'), owner => 'root', group => 'wheel', mode => '755', on_change => sub { $restart = TRUE };
$ cat <<'END' | doas tee /usr/local/bin/dserver-update-key-cache.sh #!/bin/ksh CACHEDIR=/var/run/dserver/cache DSERVER_USER=_dserver DSERVER_GROUP=_dserver echo 'Updating SSH key cache' ls /home/ | while read remoteuser; do keysfile=/home/$remoteuser/.ssh/authorized_keys if [ -f $keysfile ]; then cachefile=$CACHEDIR/$remoteuser.authorized_keys echo "Caching $keysfile -> $cachefile" cp $keysfile $cachefile chown $DSERVER_USER:$DSERVER_GROUP $cachefile chmod 600 $cachefile fi done # Cleanup obsolete public SSH keys find $CACHEDIR -name \*.authorized_keys -type f | while read cachefile; do remoteuser=$(basename $cachefile | cut -d. -f1) keysfile=/home/$remoteuser/.ssh/authorized_keys if [ ! -f $keysfile ]; then echo 'Deleting obsolete cache file $cachefile' rm $cachefile fi done echo 'All set...' END $ doas chmod 500 /usr/local/bin/dserver-update-key-cache.sh
$ echo /usr/local/bin/dserver-update-key-cache.sh | doas tee -a /etc/daily.local /usr/local/bin/dserver-update-key-cache.sh
file '/usr/local/bin/dserver-update-key-cache.sh', content => template('./scripts/dserver-update-key-cache.sh.tpl'), owner => 'root', group => 'wheel', mode => '500'; append_if_no_such_line '/etc/daily.local', '/usr/local/bin/dserver-update-key-cache.sh';
$ sudo rcctl enable dserver $ sudo rcctl start dserver $ tail -f /var/log/dserver/*.log INFO|1022-090634|Starting scheduled job runner after 2s INFO|1022-090634|Starting continuous job runner after 2s INFO|1022-090644|24204|stats.go:53|2|11|7|||MAPREDUCE:STATS|currentConnections=0|lifetimeConnections=0 INFO|1022-090654|24204|stats.go:53|2|11|7|||MAPREDUCE:STATS|currentConnections=0|lifetimeConnections=0 INFO|1022-090719|Starting server|DTail 4.1.0 Protocol 4.1 Have a lot of fun! INFO|1022-090719|Generating private server RSA host key INFO|1022-090719|Starting server INFO|1022-090719|Binding server|0.0.0.0:2222 INFO|1022-090719|Starting scheduled job runner after 2s INFO|1022-090719|Starting continuous job runner after 2s INFO|1022-090729|86050|stats.go:53|2|11|7|||MAPREDUCE:STATS|currentConnections=0|lifetimeConnections=0 INFO|1022-090739|86050|stats.go:53|2|11|7|||MAPREDUCE:STATS|currentConnections=0|lifetimeConnect . . . Ctr+C
$ doas /usr/local/bin/dserver-update-key-cache.sh Updating SSH key cache Caching /home/_dserver/.ssh/authorized_keys -> /var/cache/dserver/_dserver.authorized_keys Caching /home/admin/.ssh/authorized_keys -> /var/cache/dserver/admin.authorized_keys Caching /home/failunderd/.ssh/authorized_keys -> /var/cache/dserver/failunderd.authorized_keys Caching /home/git/.ssh/authorized_keys -> /var/cache/dserver/git.authorized_keys Caching /home/paul/.ssh/authorized_keys -> /var/cache/dserver/paul.authorized_keys Caching /home/rex/.ssh/authorized_keys -> /var/cache/dserver/rex.authorized_keys All set...
❯ ./dgrep -user rex -servers blowfish.buetow.org,fishfinger.buetow.org --regex local /etc/fstab CLIENT|earth|WARN|Encountered unknown host|{blowfish.buetow.org:2222 0xc0000a00f0 0xc0000a61e0 [blowfish.buetow.org]:2222 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9ZnF/LAk14SgqCzk38yENVTNfqibcluMTuKx1u53cKSp2xwHWzy0Ni5smFPpJDIQQljQEJl14ZdXvhhjp1kKHxJ79ubqRtIXBlC0PhlnP8Kd+mVLLHYpH9VO4rnaSfHE1kBjWkI7U6lLc6ks4flgAgGTS5Bb7pLAjwdWg794GWcnRh6kSUEQd3SftANqQLgCunDcP2Vc4KR9R78zBmEzXH/OPzl/ANgNA6wWO2OoKKy2VrjwVAab6FW15h3Lr6rYIw3KztpG+UMmEj5ReexIjXi/jUptdnUFWspvAmzIl6kwzzF8ExVyT9D75JRuHvmxXKKjyJRxqb8UnSh2JD4JN [23.88.35.144]:2222 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9ZnF/LAk14SgqCzk38yENVTNfqibcluMTuKx1u53cKSp2xwHWzy0Ni5smFPpJDIQQljQEJl14ZdXvhhjp1kKHxJ79ubqRtIXBlC0PhlnP8Kd+mVLLHYpH9VO4rnaSfHE1kBjWkI7U6lLc6ks4flgAgGTS5Bb7pLAjwdWg794GWcnRh6kSUEQd3SftANqQLgCunDcP2Vc4KR9R78zBmEzXH/OPzl/ANgNA6wWO2OoKKy2VrjwVAab6FW15h3Lr6rYIw3KztpG+UMmEj5ReexIjXi/jUptdnUFWspvAmzIl6kwzzF8ExVyT9D75JRuHvmxXKKjyJRxqb8UnSh2JD4JN 0xc0000a2180} CLIENT|earth|WARN|Encountered unknown host|{fishfinger.buetow.org:2222 0xc0000a0150 0xc000460110 [fishfinger.buetow.org]:2222 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNiikdL7+tWSN0rCaw1tOd9aQgeUFgb830V9ejkyJ5h93PKLCWZSMMCtiabc1aUeUZR//rZjcPHFLuLq/YC+Y3naYtGd6j8qVrcfG8jy3gCbs4tV9SZ9qd5E24mtYqYdGlee6JN6kEWhJxFkEwPfNlG+YAr3KC8lvEAE2JdWvaZavqsqMvHZtAX3b25WCBf2HGkyLZ+d9cnimRUOt+/+353BQFCEct/2mhMVlkr4I23CY6Tsufx0vtxx25nbFdZias6wmhxaE9p3LiWXygPWGU5iZ4RSQSImQz4zyOc9rnJeP1rwGk0OWDJhdKNXuf0kIPdzMfwxv2otgY32/DJj6L [46.23.94.99]:2222 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNiikdL7+tWSN0rCaw1tOd9aQgeUFgb830V9ejkyJ5h93PKLCWZSMMCtiabc1aUeUZR//rZjcPHFLuLq/YC+Y3naYtGd6j8qVrcfG8jy3gCbs4tV9SZ9qd5E24mtYqYdGlee6JN6kEWhJxFkEwPfNlG+YAr3KC8lvEAE2JdWvaZavqsqMvHZtAX3b25WCBf2HGkyLZ+d9cnimRUOt+/+353BQFCEct/2mhMVlkr4I23CY6Tsufx0vtxx25nbFdZias6wmhxaE9p3LiWXygPWGU5iZ4RSQSImQz4zyOc9rnJeP1rwGk0OWDJhdKNXuf0kIPdzMfwxv2otgY32/DJj6L 0xc0000a2240} Encountered 2 unknown hosts: 'blowfish.buetow.org:2222,fishfinger.buetow.org:2222' Do you want to trust these hosts?? (y=yes,a=all,n=no,d=details): a CLIENT|earth|INFO|STATS:STATS|cgocalls=11|cpu=8|connected=2|servers=2|connected%=100|new=2|throttle=0|goroutines=19 CLIENT|earth|INFO|Added hosts to known hosts file|/home/paul/.ssh/known_hosts REMOTE|blowfish|100|7|fstab|31bfd9d9a6788844.h /usr/local ffs rw,wxallowed,nodev 1 2 REMOTE|fishfinger|100|7|fstab|093f510ec5c0f512.h /usr/local ffs rw,wxallowed,nodev 1 2
❯ ./dgrep -user rex -servers blowfish.buetow.org,fishfinger.buetow.org --regex local /etc/fstab REMOTE|blowfish|100|7|fstab|31bfd9d9a6788844.h /usr/local ffs rw,wxallowed,nodev 1 2 REMOTE|fishfinger|100|7|fstab|093f510ec5c0f512.h /usr/local ffs rw,wxallowed,nodev 1 2
z z Z .--. Z Z / _(c\ .-. __ | / / '-; \'-'` `\______ \_\/'/ __/ ) / ) | \--, | \`""`__-/ .'--/ /--------\ \ \\` ///-\/ / /---;-. '-' jgs (________\ \ '-'
-=[ typewriter ]=- 1/98 .-------. _|~~ ~~ |_ =(_|_______|_)= |:::::::::| |:::::::[]| |o=======.| jgs `"""""""""`
check_dependencies () { # At least, Bash 5 is required local -i required_version=5 IFS=. read -ra version <<< "$BASH_VERSION" if [ "${version[0]}" -lt $required_version ]; then log ERROR "ERROR, \"bash\" must be at least at major version $required_version!" exit 2 fi # These must be the GNU versions of the commands for tool in $DATE $SED $GREP; do if ! $tool --version | grep -q GNU; then log ERROR "ERROR, \"$tool\" command is not the GNU version, please install!" exit 2 fi done }
./gemtexter --generate '.*hello.*'
/ _ \ The Hebern Machine \ ." ". / ___ / \ .."" "".. | O | / \ | | / \ | | --------------------------------- _/ o (O) o _ | _/ ." ". | I/ _________________/ \ | _/I ." | | ===== / I / / | ===== | | | \ | _________________." | ===== | | | | | / \ / _|_|__|_|_ __ | | | | | | | | \ "._." / o o \ ." ". | | --| --| -| / \ _/ / \ | \____\____\__| \ ______ | / | | | -------- --- / | | | ( ) (O) / \ / | ----------------------- ".__." | _|__________________________________________|_ / \ /________________________________________________\ ASCII Art by John Savard
# # $OpenBSD: acme-client.conf,v 1.4 2020/09/17 09:13:06 florian Exp $ # authority letsencrypt { api url "https://acme-v02.api.letsencrypt.org/directory" account key "/etc/acme/letsencrypt-privkey.pem" } authority letsencrypt-staging { api url "https://acme-staging-v02.api.letsencrypt.org/directory" account key "/etc/acme/letsencrypt-staging-privkey.pem" } authority buypass { api url "https://api.buypass.com/acme/directory" account key "/etc/acme/buypass-privkey.pem" contact "mailto:me@example.com" } authority buypass-test { api url "https://api.test4.buypass.no/acme/directory" account key "/etc/acme/buypass-test-privkey.pem" contact "mailto:me@example.com" } domain buetow.org { alternative names { www.buetow.org paul.buetow.org } domain key "/etc/ssl/private/buetow.org.key" domain full chain certificate "/etc/ssl/buetow.org.fullchain.pem" sign with letsencrypt } domain dtail.dev { alternative names { www.dtail.dev } domain key "/etc/ssl/private/dtail.dev.key" domain full chain certificate "/etc/ssl/dtail.dev.fullchain.pem" sign with letsencrypt } domain foo.zone { alternative names { www.foo.zone } domain key "/etc/ssl/private/foo.zone.key" domain full chain certificate "/etc/ssl/foo.zone.fullchain.pem" sign with letsencrypt } domain irregular.ninja { alternative names { www.irregular.ninja } domain key "/etc/ssl/private/irregular.ninja.key" domain full chain certificate "/etc/ssl/irregular.ninja.fullchain.pem" sign with letsencrypt } domain snonux.land { alternative names { www.snonux.land } domain key "/etc/ssl/private/snonux.land.key" domain full chain certificate "/etc/ssl/snonux.land.fullchain.pem" sign with letsencrypt }
server "foo.zone" { listen on * port 80 location "/.well-known/acme-challenge/*" { root "/acme" request strip 2 } location * { block return 302 "https://$HTTP_HOST$REQUEST_URI" } } server "foo.zone" { listen on * tls port 443 tls { certificate "/etc/ssl/foo.zone.fullchain.pem" key "/etc/ssl/private/foo.zone.key" } location * { root "/htdocs/gemtexter/foo.zone" directory auto index } }
#!/bin/sh function handle_cert { host=$1 # Create symlink, so that relayd also can read it. crt_path=/etc/ssl/$host if [ -e $crt_path.crt ]; then rm $crt_path.crt fi ln -s $crt_path.fullchain.pem $crt_path.crt # Requesting and renewing certificate. /usr/sbin/acme-client -v $host } has_update=no handle_cert www.buetow.org if [ $? -eq 0 ]; then has_update=yes fi handle_cert www.paul.buetow.org if [ $? -eq 0 ]; then has_update=yes fi handle_cert www.tmp.buetow.org if [ $? -eq 0 ]; then has_update=yes fi handle_cert www.dtail.dev if [ $? -eq 0 ]; then has_update=yes fi handle_cert www.foo.zone if [ $? -eq 0 ]; then has_update=yes fi handle_cert www.irregular.ninja if [ $? -eq 0 ]; then has_update=yes fi handle_cert www.snonux.land if [ $? -eq 0 ]; then has_update=yes fi # Pick up the new certs. if [ $has_update = yes ]; then /usr/sbin/rcctl reload httpd /usr/sbin/rcctl reload relayd /usr/sbin/rcctl restart smtpd fi
/usr/local/bin/acme.sh
Running daily.local: acme-client: /etc/ssl/buetow.org.fullchain.pem: certificate valid: 80 days left acme-client: /etc/ssl/paul.buetow.org.fullchain.pem: certificate valid: 80 days left acme-client: /etc/ssl/tmp.buetow.org.fullchain.pem: certificate valid: 80 days left acme-client: /etc/ssl/dtail.dev.fullchain.pem: certificate valid: 80 days left acme-client: /etc/ssl/foo.zone.fullchain.pem: certificate valid: 80 days left acme-client: /etc/ssl/irregular.ninja.fullchain.pem: certificate valid: 80 days left acme-client: /etc/ssl/snonux.land.fullchain.pem: certificate valid: 79 days left
our @acme_hosts = qw/buetow.org paul.buetow.org tmp.buetow.org dtail.dev foo.zone irregular.ninja snonux.land/;
group frontends => 'blowfish.buetow.org', 'twofish.buetow.org';
desc 'Configure ACME client'; task 'acme', group => 'frontends', sub { file '/etc/acme-client.conf', content => template('./etc/acme-client.conf.tpl', acme_hosts => \@acme_hosts, is_primary => $is_primary), owner => 'root', group => 'wheel', mode => '644'; file '/usr/local/bin/acme.sh', content => template('./scripts/acme.sh.tpl', acme_hosts => \@acme_hosts, is_primary => $is_primary), owner => 'root', group => 'wheel', mode => '744'; file '/etc/daily.local', ensure => 'present', owner => 'root', group => 'wheel', mode => '644'; append_if_no_such_line '/etc/daily.local', '/usr/local/bin/acme.sh'; };
desc 'Invoke ACME client'; task 'acme_invoke', group => 'frontends', sub { say run '/usr/local/bin/acme.sh'; };
# Bootstrapping the FQDN based on the server IP as the hostname and domain # facts aren't set yet due to the myname file in the first place. our $fqdns = sub { my $ipv4 = shift; return 'blowfish.buetow.org' if $ipv4 eq '23.88.35.144'; return 'twofish.buetow.org' if $ipv4 eq '108.160.134.135'; Rex::Logger::info("Unable to determine hostname for $ipv4", 'error'); return 'HOSTNAME-UNKNOWN.buetow.org'; }; # To determine whether the server is the primary or the secondary. our $is_primary = sub { my $ipv4 = shift; $fqdns->($ipv4) eq 'blowfish.buetow.org'; };
# # $OpenBSD: acme-client.conf,v 1.4 2020/09/17 09:13:06 florian Exp $ # authority letsencrypt { api url "https://acme-v02.api.letsencrypt.org/directory" account key "/etc/acme/letsencrypt-privkey.pem" } authority letsencrypt-staging { api url "https://acme-staging-v02.api.letsencrypt.org/directory" account key "/etc/acme/letsencrypt-staging-privkey.pem" } authority buypass { api url "https://api.buypass.com/acme/directory" account key "/etc/acme/buypass-privkey.pem" contact "mailto:me@example.com" } authority buypass-test { api url "https://api.test4.buypass.no/acme/directory" account key "/etc/acme/buypass-test-privkey.pem" contact "mailto:me@example.com" } <% our $primary = $is_primary->($vio0_ip); our $prefix = $primary ? '' : 'www.'; %> <% for my $host (@$acme_hosts) { %> domain <%= $prefix.$host %> { domain key "/etc/ssl/private/<%= $prefix.$host %>.key" domain full chain certificate "/etc/ssl/<%= $prefix.$host %>.fullchain.pem" sign with letsencrypt } <% } %>
#!/bin/sh <% our $primary = $is_primary->($vio0_ip); our $prefix = $primary ? '' : 'www.'; -%> function handle_cert { host=$1 # Create symlink, so that relayd also can read it. crt_path=/etc/ssl/$host if [ -e $crt_path.crt ]; then rm $crt_path.crt fi ln -s $crt_path.fullchain.pem $crt_path.crt # Requesting and renewing certificate. /usr/sbin/acme-client -v $host } has_update=no <% for my $host (@$acme_hosts) { -%> handle_cert <%= $prefix.$host %> if [ $? -eq 0 ]; then has_update=yes fi <% } -%> # Pick up the new certs. if [ $has_update = yes ]; then /usr/sbin/rcctl reload httpd /usr/sbin/rcctl reload relayd /usr/sbin/rcctl restart smtpd fi
desc 'Setup httpd'; task 'httpd', group => 'frontends', sub { append_if_no_such_line '/etc/rc.conf.local', 'httpd_flags='; file '/etc/httpd.conf', content => template('./etc/httpd.conf.tpl', acme_hosts => \@acme_hosts, is_primary => $is_primary), owner => 'root', group => 'wheel', mode => '644', on_change => sub { service 'httpd' => 'restart' }; service 'httpd', ensure => 'started'; }; desc 'Setup relayd'; task 'relayd', group => 'frontends', sub { append_if_no_such_line '/etc/rc.conf.local', 'relayd_flags='; file '/etc/relayd.conf', content => template('./etc/relayd.conf.tpl', ipv6address => $ipv6address, is_primary => $is_primary), owner => 'root', group => 'wheel', mode => '600', on_change => sub { service 'relayd' => 'restart' }; service 'relayd', ensure => 'started'; }; desc 'Setup OpenSMTPD'; task 'smtpd', group => 'frontends', sub { Rex::Logger::info('Dealing with mail aliases'); file '/etc/mail/aliases', source => './etc/mail/aliases', owner => 'root', group => 'wheel', mode => '644', on_change => sub { say run 'newaliases' }; Rex::Logger::info('Dealing with mail virtual domains'); file '/etc/mail/virtualdomains', source => './etc/mail/virtualdomains', owner => 'root', group => 'wheel', mode => '644', on_change => sub { service 'smtpd' => 'restart' }; Rex::Logger::info('Dealing with mail virtual users'); file '/etc/mail/virtualusers', source => './etc/mail/virtualusers', owner => 'root', group => 'wheel', mode => '644', on_change => sub { service 'smtpd' => 'restart' }; Rex::Logger::info('Dealing with smtpd.conf'); file '/etc/mail/smtpd.conf', content => template('./etc/mail/smtpd.conf.tpl', is_primary => $is_primary), owner => 'root', group => 'wheel', mode => '644', on_change => sub { service 'smtpd' => 'restart' }; service 'smtpd', ensure => 'started'; };
<% our $primary = $is_primary->($vio0_ip); our $prefix = $primary ? '' : 'www.'; %> # Plain HTTP for ACME and HTTPS redirect <% for my $host (@$acme_hosts) { %> server "<%= $prefix.$host %>" { listen on * port 80 location "/.well-known/acme-challenge/*" { root "/acme" request strip 2 } location * { block return 302 "https://$HTTP_HOST$REQUEST_URI" } } <% } %> # Gemtexter hosts <% for my $host (qw/foo.zone snonux.land/) { %> server "<%= $prefix.$host %>" { listen on * tls port 443 tls { certificate "/etc/ssl/<%= $prefix.$host %>.fullchain.pem" key "/etc/ssl/private/<%= $prefix.$host %>.key" } location * { root "/htdocs/gemtexter/<%= $host %>" directory auto index } } <% } %> # DTail special host server "<%= $prefix %>dtail.dev" { listen on * tls port 443 tls { certificate "/etc/ssl/<%= $prefix %>dtail.dev.fullchain.pem" key "/etc/ssl/private/<%= $prefix %>dtail.dev.key" } location * { block return 302 "https://github.dtail.dev$REQUEST_URI" } } # Irregular Ninja special host server "<%= $prefix %>irregular.ninja" { listen on * tls port 443 tls { certificate "/etc/ssl/<%= $prefix %>irregular.ninja.fullchain.pem" key "/etc/ssl/private/<%= $prefix %>irregular.ninja.key" } location * { root "/htdocs/irregular.ninja" directory auto index } } # buetow.org special host. server "<%= $prefix %>buetow.org" { listen on * tls port 443 tls { certificate "/etc/ssl/<%= $prefix %>buetow.org.fullchain.pem" key "/etc/ssl/private/<%= $prefix %>buetow.org.key" } block return 302 "https://paul.buetow.org" } server "<%= $prefix %>paul.buetow.org" { listen on * tls port 443 tls { certificate "/etc/ssl/<%= $prefix %>paul.buetow.org.fullchain.pem" key "/etc/ssl/private/<%= $prefix %>paul.buetow.org.key" } block return 302 "https://foo.zone/contact-information.html" } server "<%= $prefix %>tmp.buetow.org" { listen on * tls port 443 tls { certificate "/etc/ssl/<%= $prefix %>tmp.buetow.org.fullchain.pem" key "/etc/ssl/private/<%= $prefix %>tmp.buetow.org.key" } root "/htdocs/buetow.org/tmp" directory auto index }
<% our $primary = $is_primary->($vio0_ip); our $prefix = $primary ? '' : 'www.'; %> log connection tcp protocol "gemini" { tls keypair <%= $prefix %>foo.zone tls keypair <%= $prefix %>buetow.org } relay "gemini4" { listen on <%= $vio0_ip %> port 1965 tls protocol "gemini" forward to 127.0.0.1 port 11965 } relay "gemini6" { listen on <%= $ipv6address->($hostname) %> port 1965 tls protocol "gemini" forward to 127.0.0.1 port 11965 }
<% our $primary = $is_primary->($vio0_ip); our $prefix = $primary ? '' : 'www.'; %> pki "buetow_org_tls" cert "/etc/ssl/<%= $prefix %>buetow.org.fullchain.pem" pki "buetow_org_tls" key "/etc/ssl/private/<%= $prefix %>buetow.org.key" table aliases file:/etc/mail/aliases table virtualdomains file:/etc/mail/virtualdomains table virtualusers file:/etc/mail/virtualusers listen on socket listen on all tls pki "buetow_org_tls" hostname "<%= $prefix %>buetow.org" #listen on all action localmail mbox alias <aliases> action receive mbox virtual <virtualusers> action outbound relay match from any for domain <virtualdomains> action receive match from local for local action localmail match from local for any action outbound
rex commons
_ /_/_ .'''. =O(_)))) ...' `. jgs \_\ `. .''' `..'
❯ perl ~/git/guprecords/src/guprecords --indir=./stats/ --count=20 --all Pos | System | Kernel | Uptime | Boot time 1 | sun | FreeBSD 10.1-RELEA.. | 502d 03:29:19 | Sun Aug 16 15:56:40 2015 2 | vulcan | Linux 3.10.0-1160... | 313d 13:19:39 | Sun Jul 25 18:32:25 2021 3 | uugrn | FreeBSD 10.2-RELEASE | 303d 15:19:35 | Tue Dec 22 21:33:07 2015 4 | uugrn | FreeBSD 11.0-RELEA.. | 281d 14:38:04 | Fri Oct 21 15:22:02 2016 5 | deltavega | Linux 3.10.0-957.2.. | 279d 11:15:00 | Sun Jun 30 11:42:38 2019 6 | vulcan | Linux 3.10.0-957.2.. | 279d 11:12:14 | Sun Jun 30 11:43:41 2019 7 | deltavega | Linux 3.10.0-1160... | 253d 04:42:22 | Sat Apr 24 13:34:34 2021 8 | host0 | FreeBSD 6.2-RELEAS.. | 240d 02:23:23 | Wed Jan 31 20:34:46 2007 9 | uugrn | FreeBSD 11.1-RELEA.. | 202d 21:12:41 | Sun May 6 18:06:17 2018 10 | tauceti | Linux 3.2.0-4-amd64 | 197d 18:45:40 | Mon Dec 16 19:47:54 2013 11 | pluto | Linux 2.6.32-5-amd64 | 185d 11:53:04 | Wed Aug 1 07:34:10 2012 12 | sun | FreeBSD 10.3-RELEA.. | 164d 22:31:55 | Sat Jul 22 18:47:21 2017 13 | vulcan | Linux 3.10.0-1160... | 161d 07:08:43 | Sun Feb 14 10:05:38 2021 14 | sun | FreeBSD 10.3-RELEA.. | 158d 21:18:36 | Sat Jan 27 10:18:57 2018 15 | uugrn | FreeBSD 11.1-RELEA.. | 157d 20:57:24 | Fri Nov 3 05:02:54 2017 16 | tauceti-f | Linux 3.2.0-3-amd64 | 150d 04:12:38 | Mon Sep 16 09:02:58 2013 17 | tauceti | Linux 3.2.0-4-amd64 | 149d 09:21:43 | Mon Aug 11 09:47:50 2014 18 | pluto | Linux 3.2.0-4-amd64 | 142d 02:57:31 | Mon Sep 8 01:59:02 2014 19 | tauceti-f | Linux 3.2.0-3-amd64 | 132d 22:46:26 | Mon May 6 11:11:35 2013 20 | keppler-16b | Darwin 13.4.0 | 131d 08:17:12 | Thu Jun 11 10:44:25 2015
❯ perl ~/git/guprecords/src/guprecords --indir=./stats/ --count=20 --total Pos | System | Kernel | Uptime | 1 | uranus | Linux 5.4.17-200.f.. | 1419d 19:05:39 | 2 | sun | FreeBSD 10.1-RELEA.. | 1363d 11:41:14 | 3 | vulcan | Linux 3.10.0-1160... | 1262d 20:27:48 | 4 | uugrn | FreeBSD 10.2-RELEASE | 1219d 15:10:16 | 5 | deltavega | Linux 3.10.0-957.2.. | 1115d 06:33:55 | 6 | pluto | Linux 2.6.32-5-amd64 | 1086d 10:44:05 | 7 | tauceti | Linux 3.2.0-4-amd64 | 846d 12:58:21 | 8 | tauceti-f | Linux 3.2.0-3-amd64 | 625d 07:16:39 | 9 | host0 | FreeBSD 6.2-RELEAS.. | 534d 19:50:13 | 10 | keppler-16b | Darwin 13.4.0 | 448d 06:15:00 | 11 | tauceti-e | Linux 3.2.0-4-amd64 | 415d 18:14:13 | 12 | moon | Darwin 18.7.0 | 326d 11:21:42 | 13 | callisto | Linux 4.0.4-303.fc.. | 303d 12:18:24 | 14 | alphacentauri | FreeBSD 10.1-RELEA.. | 300d 20:15:00 | 15 | earth | Linux 5.13.14-200... | 289d 08:05:05 | 16 | makemake | Linux 5.11.9-200.f.. | 286d 21:53:03 | 17 | london | Linux 3.2.0-4-amd64 | 258d 15:10:38 | 18 | fishbone | OpenBSD 4.1 .. | 223d 05:55:26 | 19 | sagittarius | Darwin 15.6.0 | 198d 23:53:59 | 20 | mars | Linux 3.2.0-4-amd64 | 190d 05:44:21 |
# Run command 'hostname' on server foo.example.com ./rubyfy.rb -c 'hostname' <<< foo.example.com # Run command 'id' as root (via sudo) on all servers listed in the list file # Do it on 10 servers in parallel ./rubyfy.rb --parallel 10 --root --command 'id' < serverlist.txt # Run a fancy script in background on 50 servers in parallel ./rubyfy.rb -p 50 -r -b -c '/usr/local/scripts/fancy.zsh' < serverlist.txt # Grep for specific process on both servers and write output to ./out/grep.txt echo {foo,bar}.example.com | ./rubyfy.rb -p 10 -c 'pgrep -lf httpd' -n grep.txt # Reboot server only if file /var/run/maintenance.lock does NOT exist! echo foo.example.com | ./rubyfy.rb --root --command reboot --precondition /var/run/maintenance.lock
ssh dyndns@dyndnsserver /path/to/dyndns-update \ your.host.name. TYPE new-entry TIMEOUT
ssh dyndns@dyndnsserver /path/to/dyndns-update \ local.buetow.org. A 137.226.50.91 30
❯ ./cpuinfo cpuinfo (c) 1.0.2 Paul Buetow 11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz GenuineIntel 12288 KB cache p = 001 Physical processors c = 004 Cores s = 008 Siblings (Hyper-Threading enabled if s != c) v = 008 [v = p*c*(s != c ? 2 : 1)] Total logical CPUs Hyper-Threading is enabled 0003000 MHz each core 0012000 MHz total 0005990 Bogomips each processor (including virtual) 0023961 Bogomips total
Mon 20211213 50: work:5.92h Tue 20211214 50: work:7.47h lunch:0.50h pet:0.42h Wed 20211215 50: work:8.86h pet:0.50h Thu 20211216 50: work:8.02h pet:0.50h Fri 20211217 50: work:9.81h * Sat 20211218 50: work:0.00h selfdevelopment:1.00h * Sun 20211219 50: work:2.08h pet:1.00h selfdevelopment:-2.08h ================================================ balance:0.06h work:42.15h lunch:0.50h pet:2.42h selfdevelopment:-1.08h buffer:8.38h
▄ █ ▄ ▄ █ ▄ ▄ █ ▄ ▄▀█▀▄ ▄▀█▀▄ ▄▀█▀▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▀ ▀ ▀ █ ▄▄ ▄▄ █ █ █ █▀▀▀█ █ █ █ ▄▀ ▄▀▀▀▀▄ █▄ █ █▀▀▀▀▀▄ ▄▀▀▀▀▄ █ ▀▀▀█▀▀▀ ▄▀▀▀▀▄ █ ▀▀▀▀▀▀▀▀▀ █ █ ▄█ █ █ █ ▀▄ █ █▄▄▄▄▄▀ █▄▄▄▄▄▄█ █ █ █ █ █ ▄▀▀▀▀▀▀▀▀▀▀▀▄ █ █▀ ▀▄ ▀▄ ▄▀ █ ▀▄█ █ ▀▄ ▄ █ █ ▀▄ ▄▀ ▀▄█▄█▄▄▄▄▄▄▄█▄█▄▀ ▀ ▀ ▀▀▀▀ ▀ ▀ ▀ ▀▀▀▀ ▀ ▀ ▀▀▀
. + . . . . . . . . . * . * . . . . . . + . "You Are Here" . . + . . . . | . . . . . . | . . . +. + . \|/ . . . . . . V . * . . . . + . + . . . + . . + .+. . . . . + . . . . . . . . . . . . . ! / * . . . + . . - O - . . . + . . * . . / | . + . . . .. + . . . . . * . * . +.. . * . . . . . . . . + . . + - the universe
❯ where learn learn () { man $(ls /bin /sbin /usr/bin /usr/sbin 2>/dev/null | shuf -n 1) | sed -n "/^NAME/ { n;p;q }" } ❯ learn perltidy - a perl script indenter and reformatter ❯ learn timedatectl - Control the system time and date
,_---~~~~~----._ _,,_,*^____ _____``*g*\"*, ____ _____ _ _ / __/ /' ^. / \ ^@q f | _ \_ _|_ _(_) | @f | @)) | | @)) l 0 _/ | | | || |/ _` | | | \`/ \~____ / __ \_____/ \ | |_| || | (_| | | | | _l__l_ I |____/ |_|\__,_|_|_| } [______] I ] | | | | ] ~ ~ | | | | |
// Available log levels. const ( None level = iota Fatal level = iota Error level = iota Warn level = iota Info level = iota Default level = iota Verbose level = iota Debug level = iota Devel level = iota Trace level = iota All level = iota )
{ "Client": { "TermColorsEnable": true, "TermColors": { "Remote": { "DelimiterAttr": "Dim", "DelimiterBg": "Blue", "DelimiterFg": "Cyan", "RemoteAttr": "Dim", "RemoteBg": "Blue", "RemoteFg": "White", "CountAttr": "Dim", "CountBg": "Blue", "CountFg": "White", "HostnameAttr": "Bold", "HostnameBg": "Blue", "HostnameFg": "White", "IDAttr": "Dim", "IDBg": "Blue", "IDFg": "White", "StatsOkAttr": "None", "StatsOkBg": "Green", "StatsOkFg": "Black", "StatsWarnAttr": "None", "StatsWarnBg": "Red", "StatsWarnFg": "White", "TextAttr": "None", "TextBg": "Black", "TextFg": "White" }, "Client": { "DelimiterAttr": "Dim", "DelimiterBg": "Yellow", "DelimiterFg": "Black", "ClientAttr": "Dim", "ClientBg": "Yellow", "ClientFg": "Black", "HostnameAttr": "Dim", "HostnameBg": "Yellow", "HostnameFg": "Black", "TextAttr": "None", "TextBg": "Black", "TextFg": "White" }, "Server": { "DelimiterAttr": "AttrDim", "DelimiterBg": "BgCyan", "DelimiterFg": "FgBlack", "ServerAttr": "AttrDim", "ServerBg": "BgCyan", "ServerFg": "FgBlack", "HostnameAttr": "AttrBold", "HostnameBg": "BgCyan", "HostnameFg": "FgBlack", "TextAttr": "AttrNone", "TextBg": "BgBlack", "TextFg": "FgWhite" }, "Common": { "SeverityErrorAttr": "AttrBold", "SeverityErrorBg": "BgRed", "SeverityErrorFg": "FgWhite", "SeverityFatalAttr": "AttrBold", "SeverityFatalBg": "BgMagenta", "SeverityFatalFg": "FgWhite", "SeverityWarnAttr": "AttrBold", "SeverityWarnBg": "BgBlack", "SeverityWarnFg": "FgWhite" }, "MaprTable": { "DataAttr": "AttrNone", "DataBg": "BgBlue", "DataFg": "FgWhite", "DelimiterAttr": "AttrDim", "DelimiterBg": "BgBlue", "DelimiterFg": "FgWhite", "HeaderAttr": "AttrBold", "HeaderBg": "BgBlue", "HeaderFg": "FgWhite", "HeaderDelimiterAttr": "AttrDim", "HeaderDelimiterBg": "BgBlue", "HeaderDelimiterFg": "FgWhite", "HeaderSortKeyAttr": "AttrUnderline", "HeaderGroupKeyAttr": "AttrReverse", "RawQueryAttr": "AttrDim", "RawQueryBg": "BgBlack", "RawQueryFg": "FgCyan" } } }, ... }
jsonschema -i dtail.json schemas/dtail.schema.json
% dtail --files /var/log/foo.log
% dmap --files /var/log/foo.log --query 'from TABLE select .... outfile result.csv'
% dtail /var/log/foo.log
% dcat --plain /etc/passwd > /etc/test % diff /etc/test /etc/passwd # Same content, no diff
% dgrep --plain --regex 'somethingspecial' /var/log/foo.log | dmap --query 'from TABLE select .... outfile result.csv'
% awk '.....' < /some/file | dtail ....
% cat check_dtail.sh #!/bin/sh exec /usr/local/bin/dtailhealth --server localhost:2222
% export DTAIL_INTEGRATION_TEST_RUN_MODE=yes
% make . . . % go clean -testcache % go test -race -v ./integrationtests
/( )` \ \___ / | /- _ `-/ ' (/\/ \ \ /\ / / | ` \ O O ) / | `-^--'`< ' (_.) _ ) / `.___/` / `-----' / <----. __ / __ \ <----|====O)))==) \) /==== <----' `--' `.__,' \ | | \ / ______( (_ / \______ (FL) ,' ,-----' | \ `--{__________) \/ "Berkeley Unix Daemon"
[root@saturn /usr/jail/serv14/etc] # jexec 21 bash root@rhea:/ # uname -a GNU/kFreeBSD rhea.buetow.org 8.0-RELEASE-p5 FreeBSD 8.0-RELEASE-p5 #2: Sat Nov 27 13:10:09 CET 2010 root@saturn.buetow.org:/usr/obj/usr/srcs/freebsd.src8/src/sys/SERV10 x86 64 amd64 Intel(R) Core(TM) i7 CPU 920 @ 2.67GHz GNU/kFreeBSD
__ / _| ___ ___ _______ _ __ ___ | |_ / _ \ / _ \ |_ / _ \| '_ \ / _ \ | _| (_) | (_) | / / (_) | | | | __/ |_| \___/ \___(_)___\___/|_| |_|\___|
'\ '\ . . |>18>> \ \ . ' . | O>> O>> . 'o | \ .\. .. . | /\ . /\ . . | / / . / / .' . | jgs^^^^^^^`^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Art by Joan Stark, mod. by Paul Buetow
❯ ls -l /proc/self/fd/ total 0 lrwx------. 1 paul paul 64 Nov 23 09:46 0 -> /dev/pts/9 lrwx------. 1 paul paul 64 Nov 23 09:46 1 -> /dev/pts/9 lrwx------. 1 paul paul 64 Nov 23 09:46 2 -> /dev/pts/9 lr-x------. 1 paul paul 64 Nov 23 09:46 3 -> /proc/162912/fd
❯ echo Foo Foo ❯ echo Foo > /proc/self/fd/0 Foo
❯ echo Foo 1>&2 2>/dev/null Foo
❯ echo Foo 2>/dev/null 1>&2 ❯
❯ { echo Foo 1>&2; } 2>/dev/null ❯ ( echo Foo 1>&2; ) 2>/dev/null ❯ { { { echo Foo 1>&2; } 2>&1; } 1>&2; } 2>/dev/null ❯ ( ( ( echo Foo 1>&2; ) 2>&1; ) 1>&2; ) 2>/dev/null ❯
❯ lsof -a -p $$ -d0,1,2 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME bash 62676 paul 0u CHR 136,9 0t0 12 /dev/pts/9 bash 62676 paul 1u CHR 136,9 0t0 12 /dev/pts/9 bash 62676 paul 2u CHR 136,9 0t0 12 /dev/pts/9
❯ touch foo ❯ exec 3>foo # This opens fd 3 and binds it to file foo. ❯ ls -l /proc/self/fd/3 l-wx------. 1 paul paul 64 Nov 23 10:10 \ /proc/self/fd/3 -> /home/paul/foo ❯ cat foo ❯ echo Bratwurst >&3 ❯ cat foo Bratwurst ❯ exec 3>&- # This closes fd 3. ❯ echo Steak >&3 -bash: 3: Bad file descriptor
❯ cat grandmaster.sh #!/usr/bin/env bash # Write a file data-file containing two lines echo Learn You a Haskell > data-file echo for Great Good >> data-file # Link fd with fd 6 (saves default stdin) exec 6<&0 # Overwrite stdin with data-file exec < data-file # Read the first two lines from it declare LINE1 LINE2 read LINE1 read LINE2 # Print them echo First line: $LINE1 echo Second line: $LINE2 # Restore default stdin and delete fd 6 exec 0<&6 6<&-
❯ chmod 750 ./grandmaster.sh ❯ ./grandmaster.sh First line: Learn You a Haskell Second line: for Great Good
❯ cat <<END > Hello World > It’s $(date) > END Hello World It's Fri 26 Nov 08:46:52 GMT 2021
❯ <<END cat > Hello Universe > It’s $(date) > END Hello Universe It's Fri 26 Nov 08:47:32 GMT 2021
❯ declare VAR=foo ❯ if echo "$VAR" | grep -q foo; then > echo '$VAR ontains foo' > fi $VAR ontains foo
❯ if grep -q foo <<< "$VAR"; then > echo '$VAR contains foo' > fi $VAR contains foo
❯ grep -q foo <<< "$VAR" && echo '$VAR contains foo' $VAR contains foo
❯ if [[ "$VAR" =~ foo ]]; then echo yay; fi yay
❯ read a <<< ja ❯ echo $a ja ❯ read b <<< 'NEIN!!!' ❯ echo $b NEIN!!! ❯ dumdidumstring='Learn you a Golang for Great Good' ❯ read -a words <<< "$dumdidumstring" ❯ echo ${words[0]} Learn ❯ echo ${words[3]} Golang
❯ echo 'I like Perl too' > perllove.txt ❯ cat - perllove.txt <<< "$dumdidumstring" Learn you a Golang for Great Good I like Perl too
❯ echo $RANDOM 11811 ❯ echo $RANDOM 14997 ❯ echo $RANDOM 9104
❯ cat ./calc_answer_to_ultimate_question_in_life.sh #!/usr/bin/env bash declare -i MAX_DELAY=60 random_delay () { local -i sleep_for=$((RANDOM % MAX_DELAY)) echo "Delaying script execution for $sleep_for seconds..." sleep $sleep_for echo 'Continuing script execution...' } main () { random_delay # From here, do the real work. Calculating the answer to # the ultimate question can take billions of years.... : .... } main ❯ ❯ ./calc_answer_to_ultimate_question_in_life.sh Delaying script execution for 42 seconds... Continuing script execution...
❯ set -x ❯ square () { local -i num=$1; echo $((num*num)); } ❯ num=11; echo "Square of $num is $(square $num)" + num=11 ++ square 11 ++ local -i num=11 ++ echo 121 + echo 'Square of 11 is 121' Square of 11 is 121
❯ bash -x ./half_broken_script_to_be_debugged.sh
❯ bash -x ./grandmaster.sh + bash -x ./grandmaster.sh + echo Learn You a Haskell + echo for Great Good + exec + exec + declare LINE1 LINE2 + read LINE1 + read LINE2 + echo First line: Learn You a Haskell First line: Learn You a Haskell + echo Second line: for Great Good Second line: for Great Good + exec ❯
❯ help set | grep -- -e -e Exit immediately if a command exits with a non-zero status.
❯ bash -c 'set -e; echo hello; grep -q bar <<< foo; echo bar' hello ❯ echo $? 1
❯ bash -c 'set -e; echo hello; grep -q bar <<< barman; echo bar' hello bar ❯ echo $? 0
❯ bash -c 'set -e > grep -q bar <<< foo > if [ $? -eq 0 ]; then > echo "matching" > else > echo "not matching" > fi' ❯ echo $? 1
❯ bash -c 'set -e > if grep -q bar <<< foo; then > echo "matching" > else > echo "not matching" > fi' not matching ❯ echo $? 0 ❯ bash -c 'set -e > if grep -q bar <<< barman; then > echo "matching" > else > echo "not matching" > fi' matching ❯ echo $? 0
❯ cat ./e.sh #!/usr/bin/env bash set -e foo () { local arg="$1"; shift if [ -z "$arg" ]; then arg='You!' fi echo "Hello $arg" } bar () { # Temporally disable e set +e local arg="$1"; shift # Enable e again. set -e if [ -z "$arg" ]; then arg='You!' fi echo "Hello $arg" } # Will succeed bar World foo Universe bar # Will terminate the script foo ❯ ./e.sh Hello World Hello Universe Hello You!
❯ help set | grep pipefail -A 2 pipefail the return value of a pipeline is the status of the last command to exit with a non-zero status, or zero if no command exited with a non-zero status
❯ grep paul /etc/passwd | tr '[a-z]' '[A-Z]' PAUL:X:1000:1000:PAUL BUETOW:/HOME/PAUL:/BIN/BASH ❯ echo $? 0
❯ grep TheRock /etc/passwd ❯ echo $? 1 ❯ grep TheRock /etc/passwd | tr '[a-z]' '[A-Z]' ❯ echo $? 0
❯ set -o pipefail ❯ grep TheRock /etc/passwd | tr '[a-z]' '[A-Z]' ❯ echo $? 1
) ) (( ( ( )) ) ) ) // ( _ ( __ ( ~->> ,-----' |__,_~~___<'__`)-~__--__-~->> < | // : | -__ ~__ o)____)),__ - '> >- > | // : |- \_ \ -\_\ -\ \ \ ~\_ \ ->> - , >> | // : |_~_\ -\__\ \~'\ \ \, \__ . -<- >> `-----._| ` -__`-- - ~~ -- ` --~> > _/___\_ //)_`// | ||] _____[_______]_[~~-_ (.L_/ || [____________________]' `\_,/'/ ||| / ||| ,___,'./ ||| \ |||,'______| ||| / /|| I==|| ||| \ __/_|| __||__ -----||-/------`-._/||-o--o---o--- ~~~~~'
'\ . . |>18>> \ . ' . | O>> . 'o | \ . | /\ . | / / .' | jgs^^^^^^^`^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Art by Joan Stark
❯ cat < /dev/tcp/time.nist.gov/13 59536 21-11-18 08:09:16 00 0 0 153.6 UTC(NIST) *
❯ exec 5<>/dev/tcp/google.de/80 ❯ echo -e "GET / HTTP/1.1\nhost: google.de\n\n" >&5 ❯ cat <&5 | head HTTP/1.1 301 Moved Permanently Location: http://www.google.de/ Content-Type: text/html; charset=UTF-8 Date: Thu, 18 Nov 2021 08:27:18 GMT Expires: Sat, 18 Dec 2021 08:27:18 GMT Cache-Control: public, max-age=2592000 Server: gws Content-Length: 218 X-XSS-Protection: 0 X-Frame-Options: SAMEORIGIN
❯ uptime # Without process substitution 10:58:03 up 4 days, 22:08, 1 user, load average: 0.16, 0.34, 0.41 ❯ cat <(uptime) # With process substitution 10:58:16 up 4 days, 22:08, 1 user, load average: 0.14, 0.33, 0.41 ❯ stat <(uptime) File: /dev/fd/63 -> pipe:[468130] Size: 64 Blocks: 0 IO Block: 1024 symbolic link Device: 16h/22d Inode: 468137 Links: 1 Access: (0500/lr-x------) Uid: ( 1001/ paul) Gid: ( 1001/ paul) Context: unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 Access: 2021-11-20 10:59:31.482411961 +0000 Modify: 2021-11-20 10:59:31.482411961 +0000 Change: 2021-11-20 10:59:31.482411961 +0000 Birth: -
❯ echo a > /tmp/file-a.txt ❯ echo b >> /tmp/file-a.txt ❯ echo c >> /tmp/file-a.txt ❯ echo b > /tmp/file-b.txt ❯ echo a >> /tmp/file-b.txt ❯ echo c >> /tmp/file-b.txt ❯ echo X >> /tmp/file-b.txt ❯ diff -u <(sort /tmp/file-a.txt) <(sort /tmp/file-b.txt) --- /dev/fd/63 2021-11-20 11:05:03.667713554 +0000 +++ /dev/fd/62 2021-11-20 11:05:03.667713554 +0000 @@ -1,3 +1,4 @@ a b c +X ❯ echo X >> /tmp/file-a.txt # Now, both files have the same content again. ❯ diff -u <(sort /tmp/file-a.txt) <(sort /tmp/file-b.txt) ❯
❯ diff -u <(ls ./dir1/ | sort) <(ls ./dir2/ | sort)
❯ wc -l <(ls /tmp/) /etc/passwd <(env) 24 /dev/fd/63 49 /etc/passwd 24 /dev/fd/62 97 total ❯ ❯ while read foo; do > echo $foo > done < <(echo foo bar baz) foo bar baz ❯
❯ tar cjf file.tar.bz2 foo ❯ tar cjf >(bzip2 -c > file.tar.bz2) foo
❯ { ls /tmp; cat /etc/passwd; env; } | wc -l 97 ❯ ( ls /tmp; cat /etc/passwd; env; ) | wc -l 97
❯ echo $$ 62676 ❯ { echo $$; } 62676 ❯ ( echo $$; ) 62676
❯ ( env; ls ) | wc -l 27 ❯ { env; ls } | wc -l > > ^C
(list) list is executed in a subshell environment (see COMMAND EXECUTION ENVIRONMENT below). Variable assignments and builtin commands that affect the shell's environment do not remain in effect after the command completes. The return status is the exit status of list. { list; } list is simply executed in the current shell environment. list must be ter‐ minated with a newline or semicolon. This is known as a group command. The return status is the exit status of list. Note that unlike the metacharac‐ ters ( and ), { and } are reserved words and must occur where a reserved word is permitted to be recognized. Since they do not cause a word break, they must be separated from list by whitespace or another shell metacharacter.
$ Expands to the process ID of the shell. In a () subshell, it expands to the process ID of the current shell, not the subshell.
❯ echo $BASHPID; { echo $BASHPID; }; ( echo $BASHPID; ) 1028465 1028465 1028739
❯ echo {0..5} 0 1 2 3 4 5 ❯ for i in {0..5}; do echo $i; done 0 1 2 3 4 5
❯ echo {00..05} 00 01 02 03 04 05 ❯ echo {000..005} 000 001 002 003 004 005 ❯ echo {201..205} 201 202 203 204 205
❯ echo {a..e} a b c d e
❯ echo \"{These,words,are,quoted}\" "These" "words" "are" "quoted"
❯ echo {one,two}\:{A,B,C} one:A one:B one:C two:A two:B two:C ❯ echo \"{one,two}\:{A,B,C}\" "one:A" "one:B" "one:C" "two:A" "two:B" "two:C"
❯ echo Linux-{one,two,three}\:{A,B,C}-FreeBSD Linux-one:A-FreeBSD Linux-one:B-FreeBSD Linux-one:C-FreeBSD Linux-two:A-FreeBSD Linux-two:B-FreeBSD Linux-two:C-FreeBSD Linux-three:A-FreeBSD Linux-three:B-FreeBSD Linux-three:C-FreeBSD
❯ echo Hello world Hello world ❯ echo Hello world | cat - Hello world ❯ cat - <<ONECHEESEBURGERPLEASE Hello world ONECHEESEBURGERPLEASE Hello world ❯ cat - <<< 'Hello world' Hello world
❯ tar -czf - /some/dir | ssh hercules@buetow.org tar -xzvf -
$ head -n 1 grandmaster.sh #!/usr/bin/env bash $ file - < <(head -n 1 grandmaster.sh) /dev/stdin: a /usr/bin/env bash script, ASCII text executable
$ cat - hello hello ^C $ file - #!/usr/bin/perl /dev/stdin: Perl script text executable
❯ cat foo.sh #/usr/bin/env bash declare -r USER=${USER:?Missing the username} declare -r PASS=${PASS:?Missing the secret password for $USER} echo $USER:$PASS
❯ chmod +x foo.sh ❯ ./foo.sh ./foo.sh: line 3: USER: Missing the username ❯ USER=paul ./foo.sh ./foo.sh: line 4: PASS: Missing the secret password for paul ❯ echo $? 1 ❯ USER=paul PASS=secret ./foo.sh paul:secret
❯ VARIABLE1=value1 VARIABLE2=value2 ./script.sh
❯ export VARIABLE1=value1 ❯ export VARIABLE2=value2 ❯ ./script.sh
❯ help : :: : Null command. No effect; the command does nothing. Exit Status: Always succeeds.
❯ : ❯ echo $? 0
❯ while : ; do date; sleep 1; done Sun 21 Nov 12:08:31 GMT 2021 Sun 21 Nov 12:08:32 GMT 2021 Sun 21 Nov 12:08:33 GMT 2021 ^C ❯
❯ foo () { } -bash: syntax error near unexpected token `}' ❯ foo () { :; } ❯ foo ❯
❯ if foo; then :; else echo bar; fi
❯ : I am a comment and have no other effect ❯ : I am a comment and result in a syntax error () -bash: syntax error near unexpected token `(' ❯ : "I am a comment and don't result in a syntax error ()" ❯
❯ declare i=0 ❯ $[ i = i + 1 ] bash: 1: command not found... ❯ : $[ i = i + 1 ] ❯ : $[ i = i + 1 ] ❯ : $[ i = i + 1 ] ❯ echo $i 4
❯ declare j=0 ❯ let j=$((j + 1)) ❯ let j=$((j + 1)) ❯ let j=$((j + 1)) ❯ let j=$((j + 1)) ❯ echo $j 4
❯ bash -c 'echo $(( 1/10 ))' 0 ❯ zsh -c 'echo $(( 1/10 ))' 0 ❯ bash -c 'echo $(( 1/10.0 ))' bash: line 1: 1/10.0 : syntax error: invalid arithmetic operator (error token is ".0 ") ❯ zsh -c 'echo $(( 1/10.0 ))' 0.10000000000000001 ❯
❯ bc <<< 'scale=2; 1/10' .10
c=====e H ____________ _,,_H__ (__((__((___() //| | (__((__((___()()_____________________________________// |ACME | (__((__((___()()()------------------------------------' |_____| ASCII Art by Clyde Watson
_______________ |*\_/*|_______ | ___________ | .-. .-. ||_/-\_|______ | | | | | .****. .****. | | | | | | 0 0 | | .*****.*****. | | 0 0 | | | | - | | .*********. | | - | | | | \___/ | | .*******. | | \___/ | | | |___ ___| | .*****. | |___________| | |_____|\_/|_____| .***. |_______________| _|__|/ \|_|_.............*.............._|________|_ / ********** \ / ********** \ / ************ \ / ************ \ -------------------- --------------------
__ _____....--' .' ___...---'._ o -`( ___...---' \ .--. `\ ___...---' | \ \ `| | |o o | | | | \___'.-`. '. | | `---' '^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^' LGB - Art by lgbearrd
>> self => main >> self.class => Object >> self.class.included_modules => [PP::ObjectMixin, Kernel] >> Kernel.class => Module >> Kernel.methods.grep(/puts/) => [:puts] >> puts 'Hello Ruby' Hello Ruby => nil >> self.puts 'Hello World' Hello World => nil
o .,<>., o |\/\/\/\/| '========' (_ SSSSSSs )a'`SSSSSs /_ SSSSSS .=## SSSSS .#### SSSSs ###::::SSSSS .;:::""""SSS .:;:' . . \\ .::/ ' .'| .::( . | :::) \ /\( / /) ( | .' \ . ./ / _-' |\ . | _..--.. . /"---\ | ` | . | -=====================,' _ \=(*#(7.#####() | `/_.. , ( _.-''``';'-''-) ,. \ ' '+/// | .'/ \ ``-.) \ ,' _.- (( `-' `._\ `` \_/_.' ) /`-._ ) | ,'\ ,' _.'.`:-. \.-' / <_L )" | _/ `._,' ,')`; `-'`' | L / / / `. ,' ,|_/ / \ ( <_-' \ \ / `./ ' / /,' \ /|` `. | )\ /`._ ,'`._.-\ |) \' / `.' )-'.-,' )__) |\ `| : /`. `.._(--.`':`':/ \ ) \ \ |::::\ ,'/::;-)) / ( )`. | ||::::: . .::': :`-( |/ . | ||::::| . :| |==[]=: . - \ |||:::| : || : | | /\ ` | ___ ___ '|;:::| | |' \=[]=| / \ \ | /_ ||``|||::::: | ; | | | \_.'\_ `-. : \_``[]--[]|::::'\_;' )-'..`._ .-'\``:: ` . \ \___.>`''-.||:.__,' SSt |_______`> <_____:::. . . \ _/ `+a:f:......jrei'''
paul in uranus in gemtexter on 🌱 main ❯ wc -l gemtexter lib/* 117 gemtexter 59 lib/assert.source.sh 128 lib/atomfeed.source.sh 64 lib/gemfeed.source.sh 161 lib/generate.source.sh 50 lib/git.source.sh 162 lib/html.source.sh 30 lib/log.source.sh 63 lib/md.source.sh 834 total
gemtext='=> http://example.org Description of the link' assert::equals "$(generate::make_link html "$gemtext")" \ '<a class="textlink" href="http://example.org">Description of the link</a><br />'
gemtext='=> http://example.org Description of the link' assert::equals "$(generate::make_link md "$gemtext")" \ '[Description of the link](http://example.org) '
.---------------------------. /,--..---..---..---..---..--. `. //___||___||___||___||___||___\_| [j__ ######################## [_| \============================| .==| |"""||"""||"""||"""| |"""|| /======"---""---""---""---"=| =|| |____ []* ____ | ==|| // \\ // \\ |===|| hjw "\__/"---------------"\__/"-+---+'
#!/bin/bash
#!/usr/bin/env bash
# All fits on one line command1 | command2 # Long commands command1 \ | command2 \ | command3 \ | command4
# Long commands command1 | command2 | command3 | command4
greet () { local -r greeting="${1}" local -r name="${2}" echo "${greeting} ${name}!" }
say_hello_to_paul () { local -r greeting=Hello local -r name=Paul echo "$greeting $name!" }
declare FOO=bar # Curly braces around FOO are necessary echo "foo${FOO}baz"
# Prefer this: addition=$(( X + Y )) substitution="${string/#foo/bar}" # Instead of this: addition="$(expr "${X}" + "${Y}")" substitution="$(echo "${string}" | sed -e 's/^foo/bar/')"
declare -r SUGAR_FREE=yes declare -r I_NEED_THE_BUZZ=no buy_soda () { local -r sugar_free=$1 if [[ $sugar_free == yes ]]; then echo 'Diet Dr. Pepper' else echo 'Pepsi Coke' fi } buy_soda $I_NEED_THE_BUZZ
# What does this set? # Did it succeed? In part or whole? eval $(set_my_variables) # What happens if one of the returned values has a space in it? variable="$(eval some_function)"
% cat vars.source.sh declare foo=bar declare bar=baz declare bay=foo % bash -c 'source vars.source.sh; echo $foo $bar $baz' bar baz foo
% cat vars.sh #!/usr/bin/env bash cat <<END declare date="$(date)" declare user=$USER END % bash -c 'source <(./vars.sh); echo "Hello $user, it is $date"' Hello paul, it is Sat 15 May 19:21:12 BST 2021
filter_lines () { echo 'Start filtering lines in a fancy way!' >&2 grep ... | sed .... } process_lines () { echo 'Start processing line by line!' >&2 while read -r line; do ... do something and produce a result... echo "$result" done } # Do some post-processing of the data postprocess_lines () { echo 'Start removing duplicates!' >&2 sort -u } genreate_report () { echo 'My boss wants to have a report!' >&2 tee outfile.txt wc -l outfile.txt } main () { filter_lines | process_lines | postprocess_lines | generate_report } main
some_function () { local -r param_foo="$1"; shift local -r param_baz="$1"; shift local -r param_bay="$1"; shift # ... }
some_function () { local -r param_foo="$1"; shift local -r param_bar="$1"; shift local -r param_baz="$1"; shift local -r param_bay="$1"; shift # ... }
some_function () { local -r param_bar="$1"; shift local -r param_baz="$1"; shift local -r param_bay="$1"; shift # ... }
set -e grep -q foo <<< bar echo Jo
#!/usr/bin/env bash set -e some_function () { # .. some critical code # ... set +e # Grep might fail, but that's OK now grep .... local -i ec=$? set -e # .. critical code continues ... if [[ $ec -ne 0 ]]; then : # ... fi # ... }
if [[ "${my_var}" > 3 ]]; then # True for 4, false for 22. do_something fi
if (( my_var > 3 )); then do_something fi
if [[ "${my_var}" -gt 3 ]]; then do_something fi
tar -cf - ./* | ( cd "${dir}" && tar -xf - ) if (( PIPESTATUS[0] != 0 || PIPESTATUS[1] != 0 )); then echo "Unable to tar files to ${dir}" >&2 fi
tar -cf - ./* | ( cd "${DIR}" && tar -xf - ) return_codes=( "${PIPESTATUS[@]}" ) if (( return_codes[0] != 0 )); then do_something fi if (( return_codes[1] != 0 )); then do_something_else fi