From aaea51bbbee9d3f1e2719e4186e28a1193c03789 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 15 May 2021 18:38:09 +0100 Subject: some typos --- .../gemfeed/2010-04-09-standard-ml-and-haskell.gmi | 2 +- .../2011-05-07-perl-daemon-service-framework.gmi | 6 +- ...org.sh-One-Bash-script-to-rule-it-all.draft.gmi | 183 -------------------- ...org.sh-one-bash-script-to-rule-it-all.draft.gmi | 183 ++++++++++++++++++++ content/gemtext/gemfeed/atom.xml | 10 +- .../2010-04-09-standard-ml-and-haskell.html | 2 +- .../2011-05-07-perl-daemon-service-framework.html | 6 +- ...rg.sh-One-Bash-script-to-rule-it-all.draft.html | 189 --------------------- ...rg.sh-one-bash-script-to-rule-it-all.draft.html | 189 +++++++++++++++++++++ ...-15-personal-bash-coding-style-guide.draft.html | 93 ++++++++++ content/html/gemfeed/atom.xml | 10 +- .../gemfeed/2010-04-09-standard-ml-and-haskell.md | 2 +- .../2011-05-07-perl-daemon-service-framework.md | 6 +- ....org.sh-One-Bash-script-to-rule-it-all.draft.md | 183 -------------------- ....org.sh-one-bash-script-to-rule-it-all.draft.md | 183 ++++++++++++++++++++ ...05-15-personal-bash-coding-style-guide.draft.md | 67 ++++++++ 16 files changed, 737 insertions(+), 577 deletions(-) delete mode 100644 content/gemtext/gemfeed/2021-05-15-buetow.org.sh-One-Bash-script-to-rule-it-all.draft.gmi create mode 100644 content/gemtext/gemfeed/2021-05-15-buetow.org.sh-one-bash-script-to-rule-it-all.draft.gmi delete mode 100644 content/html/gemfeed/2021-05-15-buetow.org.sh-One-Bash-script-to-rule-it-all.draft.html create mode 100644 content/html/gemfeed/2021-05-15-buetow.org.sh-one-bash-script-to-rule-it-all.draft.html create mode 100644 content/html/gemfeed/2021-05-15-personal-bash-coding-style-guide.draft.html delete mode 100644 content/md/gemfeed/2021-05-15-buetow.org.sh-One-Bash-script-to-rule-it-all.draft.md create mode 100644 content/md/gemfeed/2021-05-15-buetow.org.sh-one-bash-script-to-rule-it-all.draft.md create mode 100644 content/md/gemfeed/2021-05-15-personal-bash-coding-style-guide.draft.md diff --git a/content/gemtext/gemfeed/2010-04-09-standard-ml-and-haskell.gmi b/content/gemtext/gemfeed/2010-04-09-standard-ml-and-haskell.gmi index 3d1411f7..a4a1dc57 100644 --- a/content/gemtext/gemfeed/2010-04-09-standard-ml-and-haskell.gmi +++ b/content/gemtext/gemfeed/2010-04-09-standard-ml-and-haskell.gmi @@ -4,7 +4,7 @@ I am currently looking into the functional programming language Standard ML (aka SML). The purpose is to refresh my functional programming skills and to learn something new too. Since I already know a little Haskell, could I do not help myself and I implemented the same exercises in Haskell too. -As you will see, SML and Haskell are very similar (at least when it comes to the basics). However, the syntax of Haskell is little bit more "advanced". Haskell utilises fewer keywords (e.g. no val, end, fun, fn ...). Haskell also allows to explicitly write down the function types. What I have been missing in SML so far is the so-called pattern guards. Although this is a very superficial comparison for now, so far I like Haskell more than SML. Nevertheless, I thought it would be fun to demonstrate a few simple functions of both languages to show off the similarities. +As you will see, SML and Haskell are very similar (at least when it comes to the basics). However, the syntax of Haskell is a bit more "advanced". Haskell utilizes fewer keywords (e.g. no val, end, fun, fn ...). Haskell also allows to explicitly write down the function types. What I have been missing in SML so far is the so-called pattern guards. Although this is a very superficial comparison for now, so far I like Haskell more than SML. Nevertheless, I thought it would be fun to demonstrate a few simple functions of both languages to show off the similarities. Haskell is also a "pure functional" programming language, whereas SML also makes explicit use of imperative concepts. I am by far not a specialist in either of these languages but here are a few functions implemented in both, SML and Haskell: diff --git a/content/gemtext/gemfeed/2011-05-07-perl-daemon-service-framework.gmi b/content/gemtext/gemfeed/2011-05-07-perl-daemon-service-framework.gmi index d13ff600..addd8911 100644 --- a/content/gemtext/gemfeed/2011-05-07-perl-daemon-service-framework.gmi +++ b/content/gemtext/gemfeed/2011-05-07-perl-daemon-service-framework.gmi @@ -72,7 +72,7 @@ daemon.wd=./ ## Example -So lets start the daemon with a loop interval of 10 seconds: +So let's start the daemon with a loop interval of 10 seconds: ``` $ ./control keys | grep daemon.loopinterval @@ -138,7 +138,7 @@ sub do ($) { ### Your own module -Want to give it some better use? It's just a easy as: +Want to give it some better use? It's just as easy as: ``` cd ./lib/PerlDaemonModules/ @@ -148,7 +148,7 @@ Want to give it some better use? It's just a easy as: ./bin/perldaemon restart (or shortcurt ./control restart) ``` -Now watch `./log/perldaemon.log` closely. It is a good practise to test your modules in 'foreground mode' (see above how to do that). +Now watch `./log/perldaemon.log` closely. It is a good practice to test your modules in 'foreground mode' (see above how to do that). BTW: You can install as many modules within the same instance as desired. But they are run in sequential order (in future they can also run in parallel using several threads or processes). diff --git a/content/gemtext/gemfeed/2021-05-15-buetow.org.sh-One-Bash-script-to-rule-it-all.draft.gmi b/content/gemtext/gemfeed/2021-05-15-buetow.org.sh-One-Bash-script-to-rule-it-all.draft.gmi deleted file mode 100644 index 858478aa..00000000 --- a/content/gemtext/gemfeed/2021-05-15-buetow.org.sh-One-Bash-script-to-rule-it-all.draft.gmi +++ /dev/null @@ -1,183 +0,0 @@ -# buetow.org.sh - One Bash script to rule it all - -> TODO: ADD WRITTEN BY AND CREATED AT BLABLA - -You might have read my previous blog post about entering the Geminispace. - -=> ./2021-04-24-welcome-to-the-geminispace Welcome to the Geminispace - -## Motivation - -Another benefit of using Gemini is that the Gemtext markup language is very easy to parse. As my site is dual hosted (Gemini+HTTP) I could in theory just write a shell script to deal with the conversion from Gemtext to HTML and not to rely on any external tools here. - -So I did exactly that, I wrote a Bash script which does the following: - -- Converts all Gemtext (*.gmi) files to HTML files -- Generates a Gemtext atom.xml feed for my blog posts -- Generates a HTML atom.xml feed of my blog posts - -I could have done all of that with a more powerful language than Bash (such as Perl, Ruby, Go...), but I didn't. The purpose of this exercise was to challenge what I can do with a "simple" Bash script and also to learn new things. - -``` - o .,<>., o - |\/\/\/\/| - '========' - (_ SSSSSSs - )a'`SSSSSs - /_ SSSSSS - .=## SSSSS - .#### SSSSs - ###::::SSSSS - .;:::""""SSS - .:;:' . . \\ - .::/ ' .'| - .::( . | - :::) \ - /\( / - /) ( | - .' \ . ./ / - _-' |\ . | - _..--.. . /"---\ | ` | . | - -=====================,' _ \=(*#(7.#####() | `/_.. , ( - _.-''``';'-''-) ,. \ ' '+/// | .'/ \ ``-.) \ - ,' _.- (( `-' `._\ `` \_/_.' ) /`-._ ) | - ,'\ ,' _.'.`:-. \.-' / <_L )" | - _/ `._,' ,')`; `-'`' | L / / - / `. ,' ,|_/ / \ ( <_-' \ - \ / `./ ' / /,' \ /|` `. | - )\ /`._ ,'`._.-\ |) \' - / `.' )-'.-,' )__) |\ `| - : /`. `.._(--.`':`':/ \ ) \ \ - |::::\ ,'/::;-)) / ( )`. | - ||::::: . .::': :`-( |/ . | - ||::::| . :| |==[]=: . - \ - |||:::| : || : | | /\ ` | - ___ ___ '|;:::| | |' \=[]=| / \ \ -| /_ ||``|||::::: | ; | | | \_.'\_ `-. -: \_``[]--[]|::::'\_;' )-'..`._ .-'\``:: ` . \ - \___.>`''-.||:.__,' SSt |_______`> <_____:::. . . \ _/ - `+a:f:......jrei''' -``` - -## W3C validator says all good -# -All generated HTML and Atom files pass the W3C validation. It is crazy that generating the Atom feed with valid XHTML content body for each blog posts was the most difficult part to implement in Bash. These formats are the reason why I decided to use Gemini as the primary protocol in the first place. However, Ironically I spent a couple of hours to get the XHTML and web Atoom feed working. To be fair, the Atom feed also works with Gemini. - -## Meta files for atom feed generation - -## Not without sed and grep and cut - -Soon I realised that I didn't want to go without a bit of grep and sed and cut. Regular expression matchings and simple string substitution tasks can be done in pure Bash but in my own opinion grep+sed are more powerful and easier to use (as I am used to these anyway). I managed not to use any AWK though. - -### Grepping - -I could use Bash's built-in regular expression matching engine here, but I am used to the grep pattern syntax, that's why I decided to do it this way: -``` -if grep -E -q "$IMAGE_PATTERN" <<< "$link"; then - html::img "$link" "$descr" - return -fi -``` - -### Sed-ing - -Sed comes in very handy for things like fixing HTML block text by replacing the lower than "<" and larger than ">" symbols with their corresponding HTML codes with one single command : - -``` -TODO: UPDATE SNIPPET echo "$line" | sed 's|<|\<|g; s|>|\>|g' -``` - -Sed is also useful in the following example, where the script checks whether the newly generated Atom feed file has changed compared to the previous version or not: - -``` -if ! diff -u <(sed 3d "$atom_file.tmp") <(sed 3d "$atom_file"); then - ... -else - ... -fi -``` - -### Cut-ing - -## Bash Modules for better structure - -I separated the script into different section; you could call them modules. For example, all functions dealing with the Atom feed are prefixed with atomfeed::, all functions dealing with HTML are prefixed with html:: and so on. - -As of writing this the script has the following modules and module functions: - -``` -TODO: UPDATE SNIPPET -❯ grep '::.* ()' buetow.org.sh -assert::equals () { -atom::meta () { -atom::generate () { -html::paragraph () { -html::heading () { -html::quote () { -html::img () { -html::link () { -html::gemini2html () { -html::generate () { -html::test () { -main::help () { -``` - -## Declaring all variables - -Many Bash scripts out in the wild don't have their variables declared, which leads to bad surprises as the default behaviour is that an undeclared variable is automatically a global variable once in use. So the best practise is to always declare a variable with one of the keywords "delcare", "readonly" or "local". - -Whole numbers can also have the option "-i", e.g. "declare -i num=52" and read only variables can be either declared via "readonly" or "rdeclare -r" or "local -r". Function local variables can also be declared with the "local" keyword. - -This is an example from the Atom module, where all variables are local to the function. I also make use of the "assign-then-shift"-pattern which goes like this: "local -r var1=$1; shift; local -r var2=$1; shift". The idea is that you only use "$1" to assign function arguments to named (better readable) local function variables. You will never have to bother about "$2" or above. That's is very useful when you constantly refactor your code and remove or add function arguments. It's something what I picked up from a colleague (a purely Bash wizard) some time ago: - -``` -atomfeed::meta () { - local -r now="$1"; shift - local -r gmi_file_path="$1"; shift - ... -} -``` - -## Unit tests - -Especially the Gemtext to HTML conversion part is an excellent use case for unit testing. There are unit tests for various Gemtext to HTML conversions (e.g. A header, paragraph, link, quote ...). My small unit test framework only consists of the test::assert() function. - -Forces to think creatively and to keep features fairly simple (good things) - -## De-facto templates - -## It's a static website generator - -Generate statically on my laptop and commit all statically generated files to fit. Can also preview locally. - -A lot of bash tricks - -## Config file - -## Learnings from ShellCheck - -ShellSheck: Not happy with all recommentations but most, e.g. read -r, quotes, etc. - -### While-read loops - -Specify -r - -### Warnings about variables not quoted - -### if cmd; then - -## The result(s) - -### Gemtext via Gemini protocol - -=> gemini://buetow.org gemini://buetow.org - The original Gemini capsule -=> gemini://buetow.org/gemfeed/ gemini://buetow.org/gemfeed/ - The Gemfeed -=> gemini://buetow.org/gemfeed/atom.xml gemini://buetow.org/gemfeed/atom.xml - The Atom feed - -### XHTML via HTTP protocol - -=> https://buetow.org https://buetow.org - The original Gemini capsule -=> https://buetow.org/gemfeed/ https://buetow.org/gemfeed/ - The Gemfeed -=> https://buetow.org/gemfeed/atom.xml https://buetow.org/gemfeed/atom.xml - The Atom feed - -TODO: ADD GO BACK LINK diff --git a/content/gemtext/gemfeed/2021-05-15-buetow.org.sh-one-bash-script-to-rule-it-all.draft.gmi b/content/gemtext/gemfeed/2021-05-15-buetow.org.sh-one-bash-script-to-rule-it-all.draft.gmi new file mode 100644 index 00000000..858478aa --- /dev/null +++ b/content/gemtext/gemfeed/2021-05-15-buetow.org.sh-one-bash-script-to-rule-it-all.draft.gmi @@ -0,0 +1,183 @@ +# buetow.org.sh - One Bash script to rule it all + +> TODO: ADD WRITTEN BY AND CREATED AT BLABLA + +You might have read my previous blog post about entering the Geminispace. + +=> ./2021-04-24-welcome-to-the-geminispace Welcome to the Geminispace + +## Motivation + +Another benefit of using Gemini is that the Gemtext markup language is very easy to parse. As my site is dual hosted (Gemini+HTTP) I could in theory just write a shell script to deal with the conversion from Gemtext to HTML and not to rely on any external tools here. + +So I did exactly that, I wrote a Bash script which does the following: + +- Converts all Gemtext (*.gmi) files to HTML files +- Generates a Gemtext atom.xml feed for my blog posts +- Generates a HTML atom.xml feed of my blog posts + +I could have done all of that with a more powerful language than Bash (such as Perl, Ruby, Go...), but I didn't. The purpose of this exercise was to challenge what I can do with a "simple" Bash script and also to learn new things. + +``` + o .,<>., o + |\/\/\/\/| + '========' + (_ SSSSSSs + )a'`SSSSSs + /_ SSSSSS + .=## SSSSS + .#### SSSSs + ###::::SSSSS + .;:::""""SSS + .:;:' . . \\ + .::/ ' .'| + .::( . | + :::) \ + /\( / + /) ( | + .' \ . ./ / + _-' |\ . | + _..--.. . /"---\ | ` | . | + -=====================,' _ \=(*#(7.#####() | `/_.. , ( + _.-''``';'-''-) ,. \ ' '+/// | .'/ \ ``-.) \ + ,' _.- (( `-' `._\ `` \_/_.' ) /`-._ ) | + ,'\ ,' _.'.`:-. \.-' / <_L )" | + _/ `._,' ,')`; `-'`' | L / / + / `. ,' ,|_/ / \ ( <_-' \ + \ / `./ ' / /,' \ /|` `. | + )\ /`._ ,'`._.-\ |) \' + / `.' )-'.-,' )__) |\ `| + : /`. `.._(--.`':`':/ \ ) \ \ + |::::\ ,'/::;-)) / ( )`. | + ||::::: . .::': :`-( |/ . | + ||::::| . :| |==[]=: . - \ + |||:::| : || : | | /\ ` | + ___ ___ '|;:::| | |' \=[]=| / \ \ +| /_ ||``|||::::: | ; | | | \_.'\_ `-. +: \_``[]--[]|::::'\_;' )-'..`._ .-'\``:: ` . \ + \___.>`''-.||:.__,' SSt |_______`> <_____:::. . . \ _/ + `+a:f:......jrei''' +``` + +## W3C validator says all good +# +All generated HTML and Atom files pass the W3C validation. It is crazy that generating the Atom feed with valid XHTML content body for each blog posts was the most difficult part to implement in Bash. These formats are the reason why I decided to use Gemini as the primary protocol in the first place. However, Ironically I spent a couple of hours to get the XHTML and web Atoom feed working. To be fair, the Atom feed also works with Gemini. + +## Meta files for atom feed generation + +## Not without sed and grep and cut + +Soon I realised that I didn't want to go without a bit of grep and sed and cut. Regular expression matchings and simple string substitution tasks can be done in pure Bash but in my own opinion grep+sed are more powerful and easier to use (as I am used to these anyway). I managed not to use any AWK though. + +### Grepping + +I could use Bash's built-in regular expression matching engine here, but I am used to the grep pattern syntax, that's why I decided to do it this way: +``` +if grep -E -q "$IMAGE_PATTERN" <<< "$link"; then + html::img "$link" "$descr" + return +fi +``` + +### Sed-ing + +Sed comes in very handy for things like fixing HTML block text by replacing the lower than "<" and larger than ">" symbols with their corresponding HTML codes with one single command : + +``` +TODO: UPDATE SNIPPET echo "$line" | sed 's|<|\<|g; s|>|\>|g' +``` + +Sed is also useful in the following example, where the script checks whether the newly generated Atom feed file has changed compared to the previous version or not: + +``` +if ! diff -u <(sed 3d "$atom_file.tmp") <(sed 3d "$atom_file"); then + ... +else + ... +fi +``` + +### Cut-ing + +## Bash Modules for better structure + +I separated the script into different section; you could call them modules. For example, all functions dealing with the Atom feed are prefixed with atomfeed::, all functions dealing with HTML are prefixed with html:: and so on. + +As of writing this the script has the following modules and module functions: + +``` +TODO: UPDATE SNIPPET +❯ grep '::.* ()' buetow.org.sh +assert::equals () { +atom::meta () { +atom::generate () { +html::paragraph () { +html::heading () { +html::quote () { +html::img () { +html::link () { +html::gemini2html () { +html::generate () { +html::test () { +main::help () { +``` + +## Declaring all variables + +Many Bash scripts out in the wild don't have their variables declared, which leads to bad surprises as the default behaviour is that an undeclared variable is automatically a global variable once in use. So the best practise is to always declare a variable with one of the keywords "delcare", "readonly" or "local". + +Whole numbers can also have the option "-i", e.g. "declare -i num=52" and read only variables can be either declared via "readonly" or "rdeclare -r" or "local -r". Function local variables can also be declared with the "local" keyword. + +This is an example from the Atom module, where all variables are local to the function. I also make use of the "assign-then-shift"-pattern which goes like this: "local -r var1=$1; shift; local -r var2=$1; shift". The idea is that you only use "$1" to assign function arguments to named (better readable) local function variables. You will never have to bother about "$2" or above. That's is very useful when you constantly refactor your code and remove or add function arguments. It's something what I picked up from a colleague (a purely Bash wizard) some time ago: + +``` +atomfeed::meta () { + local -r now="$1"; shift + local -r gmi_file_path="$1"; shift + ... +} +``` + +## Unit tests + +Especially the Gemtext to HTML conversion part is an excellent use case for unit testing. There are unit tests for various Gemtext to HTML conversions (e.g. A header, paragraph, link, quote ...). My small unit test framework only consists of the test::assert() function. + +Forces to think creatively and to keep features fairly simple (good things) + +## De-facto templates + +## It's a static website generator + +Generate statically on my laptop and commit all statically generated files to fit. Can also preview locally. + +A lot of bash tricks + +## Config file + +## Learnings from ShellCheck + +ShellSheck: Not happy with all recommentations but most, e.g. read -r, quotes, etc. + +### While-read loops + +Specify -r + +### Warnings about variables not quoted + +### if cmd; then + +## The result(s) + +### Gemtext via Gemini protocol + +=> gemini://buetow.org gemini://buetow.org - The original Gemini capsule +=> gemini://buetow.org/gemfeed/ gemini://buetow.org/gemfeed/ - The Gemfeed +=> gemini://buetow.org/gemfeed/atom.xml gemini://buetow.org/gemfeed/atom.xml - The Atom feed + +### XHTML via HTTP protocol + +=> https://buetow.org https://buetow.org - The original Gemini capsule +=> https://buetow.org/gemfeed/ https://buetow.org/gemfeed/ - The Gemfeed +=> https://buetow.org/gemfeed/atom.xml https://buetow.org/gemfeed/atom.xml - The Atom feed + +TODO: ADD GO BACK LINK diff --git a/content/gemtext/gemfeed/atom.xml b/content/gemtext/gemfeed/atom.xml index 89cd5036..5f738cc1 100644 --- a/content/gemtext/gemfeed/atom.xml +++ b/content/gemtext/gemfeed/atom.xml @@ -1,6 +1,6 @@ - 2021-05-14T23:00:11+01:00 + 2021-05-15T18:38:00+01:00 buetow.org feed Having fun with computers! @@ -749,7 +749,7 @@ daemon.alivefile=./run/perldaemon.alive daemon.wd=./

Example

-

So lets start the daemon with a loop interval of 10 seconds:

+

So let's start the daemon with a loop interval of 10 seconds:

 $ ./control keys | grep daemon.loopinterval
 daemon.loopinterval=1
@@ -804,7 +804,7 @@ sub do ($) {
 1;
 

Your own module

-

Want to give it some better use? It's just a easy as:

+

Want to give it some better use? It's just as easy as:

  cd ./lib/PerlDaemonModules/
  cp ExampleModule.pm YourModule.pm
@@ -812,7 +812,7 @@ sub do ($) {
  cd -
  ./bin/perldaemon restart (or shortcurt ./control restart)
 
-

Now watch `./log/perldaemon.log` closely. It is a good practise to test your modules in 'foreground mode' (see above how to do that).

+

Now watch `./log/perldaemon.log` closely. It is a good practice to test your modules in 'foreground mode' (see above how to do that).

BTW: You can install as many modules within the same instance as desired. But they are run in sequential order (in future they can also run in parallel using several threads or processes).

May the source be with you

You can find PerlDaemon (including the examples) at:

@@ -1251,7 +1251,7 @@ BB

Standard ML and Haskell

Written by Paul Buetow 2010-04-09

I am currently looking into the functional programming language Standard ML (aka SML). The purpose is to refresh my functional programming skills and to learn something new too. Since I already know a little Haskell, could I do not help myself and I implemented the same exercises in Haskell too.

-

As you will see, SML and Haskell are very similar (at least when it comes to the basics). However, the syntax of Haskell is little bit more "advanced". Haskell utilises fewer keywords (e.g. no val, end, fun, fn ...). Haskell also allows to explicitly write down the function types. What I have been missing in SML so far is the so-called pattern guards. Although this is a very superficial comparison for now, so far I like Haskell more than SML. Nevertheless, I thought it would be fun to demonstrate a few simple functions of both languages to show off the similarities.

+

As you will see, SML and Haskell are very similar (at least when it comes to the basics). However, the syntax of Haskell is a bit more "advanced". Haskell utilizes fewer keywords (e.g. no val, end, fun, fn ...). Haskell also allows to explicitly write down the function types. What I have been missing in SML so far is the so-called pattern guards. Although this is a very superficial comparison for now, so far I like Haskell more than SML. Nevertheless, I thought it would be fun to demonstrate a few simple functions of both languages to show off the similarities.

Haskell is also a "pure functional" programming language, whereas SML also makes explicit use of imperative concepts. I am by far not a specialist in either of these languages but here are a few functions implemented in both, SML and Haskell:

Defining a multi data type

Standard ML:

diff --git a/content/html/gemfeed/2010-04-09-standard-ml-and-haskell.html b/content/html/gemfeed/2010-04-09-standard-ml-and-haskell.html index cde7ddb8..d96fdf27 100644 --- a/content/html/gemfeed/2010-04-09-standard-ml-and-haskell.html +++ b/content/html/gemfeed/2010-04-09-standard-ml-and-haskell.html @@ -55,7 +55,7 @@ h2, h3 {

Standard ML and Haskell

Written by Paul Buetow 2010-04-09

I am currently looking into the functional programming language Standard ML (aka SML). The purpose is to refresh my functional programming skills and to learn something new too. Since I already know a little Haskell, could I do not help myself and I implemented the same exercises in Haskell too.

-

As you will see, SML and Haskell are very similar (at least when it comes to the basics). However, the syntax of Haskell is little bit more "advanced". Haskell utilises fewer keywords (e.g. no val, end, fun, fn ...). Haskell also allows to explicitly write down the function types. What I have been missing in SML so far is the so-called pattern guards. Although this is a very superficial comparison for now, so far I like Haskell more than SML. Nevertheless, I thought it would be fun to demonstrate a few simple functions of both languages to show off the similarities.

+

As you will see, SML and Haskell are very similar (at least when it comes to the basics). However, the syntax of Haskell is a bit more "advanced". Haskell utilizes fewer keywords (e.g. no val, end, fun, fn ...). Haskell also allows to explicitly write down the function types. What I have been missing in SML so far is the so-called pattern guards. Although this is a very superficial comparison for now, so far I like Haskell more than SML. Nevertheless, I thought it would be fun to demonstrate a few simple functions of both languages to show off the similarities.

Haskell is also a "pure functional" programming language, whereas SML also makes explicit use of imperative concepts. I am by far not a specialist in either of these languages but here are a few functions implemented in both, SML and Haskell:

Defining a multi data type

Standard ML:

diff --git a/content/html/gemfeed/2011-05-07-perl-daemon-service-framework.html b/content/html/gemfeed/2011-05-07-perl-daemon-service-framework.html index 379e4361..fd73746f 100644 --- a/content/html/gemfeed/2011-05-07-perl-daemon-service-framework.html +++ b/content/html/gemfeed/2011-05-07-perl-daemon-service-framework.html @@ -114,7 +114,7 @@ daemon.alivefile=./run/perldaemon.alive daemon.wd=./

Example

-

So lets start the daemon with a loop interval of 10 seconds:

+

So let's start the daemon with a loop interval of 10 seconds:

 $ ./control keys | grep daemon.loopinterval
 daemon.loopinterval=1
@@ -169,7 +169,7 @@ sub do ($) {
 1;
 

Your own module

-

Want to give it some better use? It's just a easy as:

+

Want to give it some better use? It's just as easy as:

  cd ./lib/PerlDaemonModules/
  cp ExampleModule.pm YourModule.pm
@@ -177,7 +177,7 @@ sub do ($) {
  cd -
  ./bin/perldaemon restart (or shortcurt ./control restart)
 
-

Now watch `./log/perldaemon.log` closely. It is a good practise to test your modules in 'foreground mode' (see above how to do that).

+

Now watch `./log/perldaemon.log` closely. It is a good practice to test your modules in 'foreground mode' (see above how to do that).

BTW: You can install as many modules within the same instance as desired. But they are run in sequential order (in future they can also run in parallel using several threads or processes).

May the source be with you

You can find PerlDaemon (including the examples) at:

diff --git a/content/html/gemfeed/2021-05-15-buetow.org.sh-One-Bash-script-to-rule-it-all.draft.html b/content/html/gemfeed/2021-05-15-buetow.org.sh-One-Bash-script-to-rule-it-all.draft.html deleted file mode 100644 index 7d47bdd6..00000000 --- a/content/html/gemfeed/2021-05-15-buetow.org.sh-One-Bash-script-to-rule-it-all.draft.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - -Having fun with computers! - - - - -

buetow.org.sh - One Bash script to rule it all

-

TODO: ADD WRITTEN BY AND CREATED AT BLABLA

-

You might have read my previous blog post about entering the Geminispace.

-Welcome to the Geminispace
-

Motivation

-

Another benefit of using Gemini is that the Gemtext markup language is very easy to parse. As my site is dual hosted (Gemini+HTTP) I could in theory just write a shell script to deal with the conversion from Gemtext to HTML and not to rely on any external tools here.

-

So I did exactly that, I wrote a Bash script which does the following:

-

- Converts all Gemtext (*.gmi) files to HTML files

-

- Generates a Gemtext atom.xml feed for my blog posts

-

- Generates a HTML atom.xml feed of my blog posts

-

I could have done all of that with a more powerful language than Bash (such as Perl, Ruby, Go...), but I didn't. The purpose of this exercise was to challenge what I can do with a "simple" Bash script and also to learn new things.

-
-                                                               o .,<>., o
-                                                               |\/\/\/\/|
-                                                               '========'
-                                                               (_ SSSSSSs
-                                                               )a'`SSSSSs
-                                                              /_   SSSSSS
-                                                              .=## SSSSS
-                                                              .####  SSSSs
-                                                              ###::::SSSSS
-                                                             .;:::""""SSS
-                                                            .:;:'  . .  \\
-                                                           .::/  '     .'|
-                                                          .::( .         |
-                                                          :::)           \
-                                                          /\(            /
-                                                         /)            ( |
-                                                       .'  \  .       ./ /
-                                                    _-'    |\  .        |
-                                  _..--..   .  /"---\      | ` |      . |
-          -=====================,' _     \=(*#(7.#####()   |  `/_..   , (
-                      _.-''``';'-''-) ,.  \ '  '+/// |   .'/   \  ``-.) \
-                    ,'  _.-  ((    `-'  `._\    `` \_/_.'  )    /`-._  ) |
-                  ,'\ ,'  _.'.`:-.    \.-'                 /   <_L   )"  |
-                _/   `._,' ,')`;  `-'`'                    |     L  /    /
-               / `.   ,' ,|_/ / \                          (    <_-'     \
-               \ / `./  '  / /,' \                        /|`         `. |
-               )\   /`._   ,'`._.-\                       |)            \'
-              /  `.'    )-'.-,' )__)                      |\            `|
-             : /`. `.._(--.`':`':/ \                      ) \             \
-             |::::\     ,'/::;-))  /                      ( )`.            |
-             ||:::::  . .::':  :`-(                       |/    .          |
-             ||::::|  . :|  |==[]=:                       .        -       \
-             |||:::|  : ||  :  |  |                      /\           `     |
- ___ ___     '|;:::|  | |'   \=[]=|                     /  \                \
-|   /_  ||``|||:::::  | ;    | |  |                     \_.'\_               `-.
-:   \_``[]--[]|::::'\_;'     )-'..`._                 .-'\``:: ` .              \
- \___.>`''-.||:.__,'     SSt |_______`>              <_____:::.         . . \  _/
-                                                           `+a:f:......jrei'''
-
-

W3C validator says all good

-

#

-

All generated HTML and Atom files pass the W3C validation. It is crazy that generating the Atom feed with valid XHTML content body for each blog posts was the most difficult part to implement in Bash. These formats are the reason why I decided to use Gemini as the primary protocol in the first place. However, Ironically I spent a couple of hours to get the XHTML and web Atoom feed working. To be fair, the Atom feed also works with Gemini.

-

Meta files for atom feed generation

-

Not without sed and grep and cut

-

Soon I realised that I didn't want to go without a bit of grep and sed and cut. Regular expression matchings and simple string substitution tasks can be done in pure Bash but in my own opinion grep+sed are more powerful and easier to use (as I am used to these anyway). I managed not to use any AWK though.

-

Grepping

-

I could use Bash's built-in regular expression matching engine here, but I am used to the grep pattern syntax, that's why I decided to do it this way:

-
-if grep -E -q "$IMAGE_PATTERN" <<< "$link"; then
-    html::img "$link" "$descr"
-    return
-fi
-
-

Sed-ing

-

Sed comes in very handy for things like fixing HTML block text by replacing the lower than "<" and larger than ">" symbols with their corresponding HTML codes with one single command :

-
-TODO: UPDATE SNIPPET echo "$line" | sed 's|<|\&lt;|g; s|>|\&gt;|g'
-
-

Sed is also useful in the following example, where the script checks whether the newly generated Atom feed file has changed compared to the previous version or not:

-
-if ! diff -u <(sed 3d "$atom_file.tmp") <(sed 3d "$atom_file"); then
-    ... 
-else
-    ...
-fi
-
-

Cut-ing

-

Bash Modules for better structure

-

I separated the script into different section; you could call them modules. For example, all functions dealing with the Atom feed are prefixed with atomfeed::, all functions dealing with HTML are prefixed with html:: and so on.

-

As of writing this the script has the following modules and module functions:

-
-TODO: UPDATE SNIPPET
-❯ grep '::.* ()' buetow.org.sh
-assert::equals () {
-atom::meta () {
-atom::generate () {
-html::paragraph () {
-html::heading () {
-html::quote () {
-html::img () {
-html::link () {
-html::gemini2html () {
-html::generate () {
-html::test () {
-main::help () {
-
-

Declaring all variables

-

Many Bash scripts out in the wild don't have their variables declared, which leads to bad surprises as the default behaviour is that an undeclared variable is automatically a global variable once in use. So the best practise is to always declare a variable with one of the keywords "delcare", "readonly" or "local".

-

Whole numbers can also have the option "-i", e.g. "declare -i num=52" and read only variables can be either declared via "readonly" or "rdeclare -r" or "local -r". Function local variables can also be declared with the "local" keyword.

-

This is an example from the Atom module, where all variables are local to the function. I also make use of the "assign-then-shift"-pattern which goes like this: "local -r var1=$1; shift; local -r var2=$1; shift". The idea is that you only use "$1" to assign function arguments to named (better readable) local function variables. You will never have to bother about "$2" or above. That's is very useful when you constantly refactor your code and remove or add function arguments. It's something what I picked up from a colleague (a purely Bash wizard) some time ago:

-
-atomfeed::meta () {
-    local -r now="$1"; shift
-    local -r gmi_file_path="$1"; shift
-    ...
-}
-
-

Unit tests

-

Especially the Gemtext to HTML conversion part is an excellent use case for unit testing. There are unit tests for various Gemtext to HTML conversions (e.g. A header, paragraph, link, quote ...). My small unit test framework only consists of the test::assert() function.

-

Forces to think creatively and to keep features fairly simple (good things)

-

De-facto templates

-

It's a static website generator

-

Generate statically on my laptop and commit all statically generated files to fit. Can also preview locally.

-

A lot of bash tricks

-

Config file

-

Learnings from ShellCheck

-

ShellSheck: Not happy with all recommentations but most, e.g. read -r, quotes, etc.

-

While-read loops

-

Specify -r

-

Warnings about variables not quoted

-

if cmd; then

-

The result(s)

-

Gemtext via Gemini protocol

-gemini://buetow.org - The original Gemini capsule
-gemini://buetow.org/gemfeed/ - The Gemfeed
-gemini://buetow.org/gemfeed/atom.xml - The Atom feed
-

XHTML via HTTP protocol

-https://buetow.org - The original Gemini capsule
-https://buetow.org/gemfeed/ - The Gemfeed
-https://buetow.org/gemfeed/atom.xml - The Atom feed
-

TODO: ADD GO BACK LINK

- - diff --git a/content/html/gemfeed/2021-05-15-buetow.org.sh-one-bash-script-to-rule-it-all.draft.html b/content/html/gemfeed/2021-05-15-buetow.org.sh-one-bash-script-to-rule-it-all.draft.html new file mode 100644 index 00000000..7d47bdd6 --- /dev/null +++ b/content/html/gemfeed/2021-05-15-buetow.org.sh-one-bash-script-to-rule-it-all.draft.html @@ -0,0 +1,189 @@ + + + + +Having fun with computers! + + + + +

buetow.org.sh - One Bash script to rule it all

+

TODO: ADD WRITTEN BY AND CREATED AT BLABLA

+

You might have read my previous blog post about entering the Geminispace.

+Welcome to the Geminispace
+

Motivation

+

Another benefit of using Gemini is that the Gemtext markup language is very easy to parse. As my site is dual hosted (Gemini+HTTP) I could in theory just write a shell script to deal with the conversion from Gemtext to HTML and not to rely on any external tools here.

+

So I did exactly that, I wrote a Bash script which does the following:

+

- Converts all Gemtext (*.gmi) files to HTML files

+

- Generates a Gemtext atom.xml feed for my blog posts

+

- Generates a HTML atom.xml feed of my blog posts

+

I could have done all of that with a more powerful language than Bash (such as Perl, Ruby, Go...), but I didn't. The purpose of this exercise was to challenge what I can do with a "simple" Bash script and also to learn new things.

+
+                                                               o .,<>., o
+                                                               |\/\/\/\/|
+                                                               '========'
+                                                               (_ SSSSSSs
+                                                               )a'`SSSSSs
+                                                              /_   SSSSSS
+                                                              .=## SSSSS
+                                                              .####  SSSSs
+                                                              ###::::SSSSS
+                                                             .;:::""""SSS
+                                                            .:;:'  . .  \\
+                                                           .::/  '     .'|
+                                                          .::( .         |
+                                                          :::)           \
+                                                          /\(            /
+                                                         /)            ( |
+                                                       .'  \  .       ./ /
+                                                    _-'    |\  .        |
+                                  _..--..   .  /"---\      | ` |      . |
+          -=====================,' _     \=(*#(7.#####()   |  `/_..   , (
+                      _.-''``';'-''-) ,.  \ '  '+/// |   .'/   \  ``-.) \
+                    ,'  _.-  ((    `-'  `._\    `` \_/_.'  )    /`-._  ) |
+                  ,'\ ,'  _.'.`:-.    \.-'                 /   <_L   )"  |
+                _/   `._,' ,')`;  `-'`'                    |     L  /    /
+               / `.   ,' ,|_/ / \                          (    <_-'     \
+               \ / `./  '  / /,' \                        /|`         `. |
+               )\   /`._   ,'`._.-\                       |)            \'
+              /  `.'    )-'.-,' )__)                      |\            `|
+             : /`. `.._(--.`':`':/ \                      ) \             \
+             |::::\     ,'/::;-))  /                      ( )`.            |
+             ||:::::  . .::':  :`-(                       |/    .          |
+             ||::::|  . :|  |==[]=:                       .        -       \
+             |||:::|  : ||  :  |  |                      /\           `     |
+ ___ ___     '|;:::|  | |'   \=[]=|                     /  \                \
+|   /_  ||``|||:::::  | ;    | |  |                     \_.'\_               `-.
+:   \_``[]--[]|::::'\_;'     )-'..`._                 .-'\``:: ` .              \
+ \___.>`''-.||:.__,'     SSt |_______`>              <_____:::.         . . \  _/
+                                                           `+a:f:......jrei'''
+
+

W3C validator says all good

+

#

+

All generated HTML and Atom files pass the W3C validation. It is crazy that generating the Atom feed with valid XHTML content body for each blog posts was the most difficult part to implement in Bash. These formats are the reason why I decided to use Gemini as the primary protocol in the first place. However, Ironically I spent a couple of hours to get the XHTML and web Atoom feed working. To be fair, the Atom feed also works with Gemini.

+

Meta files for atom feed generation

+

Not without sed and grep and cut

+

Soon I realised that I didn't want to go without a bit of grep and sed and cut. Regular expression matchings and simple string substitution tasks can be done in pure Bash but in my own opinion grep+sed are more powerful and easier to use (as I am used to these anyway). I managed not to use any AWK though.

+

Grepping

+

I could use Bash's built-in regular expression matching engine here, but I am used to the grep pattern syntax, that's why I decided to do it this way:

+
+if grep -E -q "$IMAGE_PATTERN" <<< "$link"; then
+    html::img "$link" "$descr"
+    return
+fi
+
+

Sed-ing

+

Sed comes in very handy for things like fixing HTML block text by replacing the lower than "<" and larger than ">" symbols with their corresponding HTML codes with one single command :

+
+TODO: UPDATE SNIPPET echo "$line" | sed 's|<|\&lt;|g; s|>|\&gt;|g'
+
+

Sed is also useful in the following example, where the script checks whether the newly generated Atom feed file has changed compared to the previous version or not:

+
+if ! diff -u <(sed 3d "$atom_file.tmp") <(sed 3d "$atom_file"); then
+    ... 
+else
+    ...
+fi
+
+

Cut-ing

+

Bash Modules for better structure

+

I separated the script into different section; you could call them modules. For example, all functions dealing with the Atom feed are prefixed with atomfeed::, all functions dealing with HTML are prefixed with html:: and so on.

+

As of writing this the script has the following modules and module functions:

+
+TODO: UPDATE SNIPPET
+❯ grep '::.* ()' buetow.org.sh
+assert::equals () {
+atom::meta () {
+atom::generate () {
+html::paragraph () {
+html::heading () {
+html::quote () {
+html::img () {
+html::link () {
+html::gemini2html () {
+html::generate () {
+html::test () {
+main::help () {
+
+

Declaring all variables

+

Many Bash scripts out in the wild don't have their variables declared, which leads to bad surprises as the default behaviour is that an undeclared variable is automatically a global variable once in use. So the best practise is to always declare a variable with one of the keywords "delcare", "readonly" or "local".

+

Whole numbers can also have the option "-i", e.g. "declare -i num=52" and read only variables can be either declared via "readonly" or "rdeclare -r" or "local -r". Function local variables can also be declared with the "local" keyword.

+

This is an example from the Atom module, where all variables are local to the function. I also make use of the "assign-then-shift"-pattern which goes like this: "local -r var1=$1; shift; local -r var2=$1; shift". The idea is that you only use "$1" to assign function arguments to named (better readable) local function variables. You will never have to bother about "$2" or above. That's is very useful when you constantly refactor your code and remove or add function arguments. It's something what I picked up from a colleague (a purely Bash wizard) some time ago:

+
+atomfeed::meta () {
+    local -r now="$1"; shift
+    local -r gmi_file_path="$1"; shift
+    ...
+}
+
+

Unit tests

+

Especially the Gemtext to HTML conversion part is an excellent use case for unit testing. There are unit tests for various Gemtext to HTML conversions (e.g. A header, paragraph, link, quote ...). My small unit test framework only consists of the test::assert() function.

+

Forces to think creatively and to keep features fairly simple (good things)

+

De-facto templates

+

It's a static website generator

+

Generate statically on my laptop and commit all statically generated files to fit. Can also preview locally.

+

A lot of bash tricks

+

Config file

+

Learnings from ShellCheck

+

ShellSheck: Not happy with all recommentations but most, e.g. read -r, quotes, etc.

+

While-read loops

+

Specify -r

+

Warnings about variables not quoted

+

if cmd; then

+

The result(s)

+

Gemtext via Gemini protocol

+gemini://buetow.org - The original Gemini capsule
+gemini://buetow.org/gemfeed/ - The Gemfeed
+gemini://buetow.org/gemfeed/atom.xml - The Atom feed
+

XHTML via HTTP protocol

+https://buetow.org - The original Gemini capsule
+https://buetow.org/gemfeed/ - The Gemfeed
+https://buetow.org/gemfeed/atom.xml - The Atom feed
+

TODO: ADD GO BACK LINK

+ + diff --git a/content/html/gemfeed/2021-05-15-personal-bash-coding-style-guide.draft.html b/content/html/gemfeed/2021-05-15-personal-bash-coding-style-guide.draft.html new file mode 100644 index 00000000..44ad0784 --- /dev/null +++ b/content/html/gemfeed/2021-05-15-personal-bash-coding-style-guide.draft.html @@ -0,0 +1,93 @@ + + + + +Having fun with computers! + + + + +

Personal Bash coding style guide

+
+   .---------------------------.
+  /,--..---..---..---..---..--. `.
+ //___||___||___||___||___||___\_|
+ [j__ ######################## [_|
+    \============================|
+ .==|  |"""||"""||"""||"""| |"""||
+/======"---""---""---""---"=|  =||
+|____    []*          ____  | ==||
+//  \\               //  \\ |===||  hjw
+"\__/"---------------"\__/"-+---+'
+
+

Written by Paul Buetow 2021-15-21

+

Lately, I have been polishing and writing a lot of Bash code. Not that I never wrote a lot of Bash, but now as I also looked through the "Google Shell Style Guide" I thought it is time to also write my thoughts on that. I agree to that guide in most, but not in all points.

+Gogle Shell Style Guide
+

I also highly recommend to have a read through the "Advanced Bash-Scripting Guide" (which is not from Google but written by Mendel Cooper). I learn something new every time I have a look at it.

+Advanced Bash-Scripting Guide
+

My modifications

+

These are my personal modifications of the Google Guide.

+

2 space soft-tabs indentation

+

I know there have been many tab and soft-tab wars on this planet. Google recommends to use 2 space soft-tabs.

+

My own reality is I don't really care if I use 2 or 4 space indentations. I agree however that tabs should not be used. I personally tend to use 4 space soft-tabs as that's currently how my personal Vim is configured for any programming languages. What matters most though is consistency within the same script/project.

+

Google also recommends to limit line length to 80 characters. For some people that seem's to be an ancient habit from the 80's, where all computer terminals couldn't display longer lines. But I think that the 80 character mark is still a good practise at least for shell scripts. For example I am often writing code on a Microsoft Go Tablet PC (running Linux of course) and it comes in very handy if the lines are not too long due to the relatively small display on the device.

+

I hit the 80 character line length quicker with the 4 spaces, but that makes me refactor the Bash code more aggressively which is actually a good thing.

+

Breaking long pipes

+

Quoting your variables

+

Prefer internal over external commands

+

My additions

+

Use of 'yes' and 'no'

+

Non-evil alternative to variable assignments via eval

+

Prefer pipes over arrays for list processing

+

Learned

+

Strucking me

+

PIPESTATUS

+

E-Mail me your thoughts at comments@mx.buetow.org!

+Go back to the main site
+ + diff --git a/content/html/gemfeed/atom.xml b/content/html/gemfeed/atom.xml index b351cf62..35a58e5a 100644 --- a/content/html/gemfeed/atom.xml +++ b/content/html/gemfeed/atom.xml @@ -1,6 +1,6 @@ - 2021-05-14T23:00:11+01:00 + 2021-05-15T18:38:00+01:00 buetow.org feed Having fun with computers! @@ -749,7 +749,7 @@ daemon.alivefile=./run/perldaemon.alive daemon.wd=./

Example

-

So lets start the daemon with a loop interval of 10 seconds:

+

So let's start the daemon with a loop interval of 10 seconds:

 $ ./control keys | grep daemon.loopinterval
 daemon.loopinterval=1
@@ -804,7 +804,7 @@ sub do ($) {
 1;
 

Your own module

-

Want to give it some better use? It's just a easy as:

+

Want to give it some better use? It's just as easy as:

  cd ./lib/PerlDaemonModules/
  cp ExampleModule.pm YourModule.pm
@@ -812,7 +812,7 @@ sub do ($) {
  cd -
  ./bin/perldaemon restart (or shortcurt ./control restart)
 
-

Now watch `./log/perldaemon.log` closely. It is a good practise to test your modules in 'foreground mode' (see above how to do that).

+

Now watch `./log/perldaemon.log` closely. It is a good practice to test your modules in 'foreground mode' (see above how to do that).

BTW: You can install as many modules within the same instance as desired. But they are run in sequential order (in future they can also run in parallel using several threads or processes).

May the source be with you

You can find PerlDaemon (including the examples) at:

@@ -1251,7 +1251,7 @@ BB

Standard ML and Haskell

Written by Paul Buetow 2010-04-09

I am currently looking into the functional programming language Standard ML (aka SML). The purpose is to refresh my functional programming skills and to learn something new too. Since I already know a little Haskell, could I do not help myself and I implemented the same exercises in Haskell too.

-

As you will see, SML and Haskell are very similar (at least when it comes to the basics). However, the syntax of Haskell is little bit more "advanced". Haskell utilises fewer keywords (e.g. no val, end, fun, fn ...). Haskell also allows to explicitly write down the function types. What I have been missing in SML so far is the so-called pattern guards. Although this is a very superficial comparison for now, so far I like Haskell more than SML. Nevertheless, I thought it would be fun to demonstrate a few simple functions of both languages to show off the similarities.

+

As you will see, SML and Haskell are very similar (at least when it comes to the basics). However, the syntax of Haskell is a bit more "advanced". Haskell utilizes fewer keywords (e.g. no val, end, fun, fn ...). Haskell also allows to explicitly write down the function types. What I have been missing in SML so far is the so-called pattern guards. Although this is a very superficial comparison for now, so far I like Haskell more than SML. Nevertheless, I thought it would be fun to demonstrate a few simple functions of both languages to show off the similarities.

Haskell is also a "pure functional" programming language, whereas SML also makes explicit use of imperative concepts. I am by far not a specialist in either of these languages but here are a few functions implemented in both, SML and Haskell:

Defining a multi data type

Standard ML:

diff --git a/content/md/gemfeed/2010-04-09-standard-ml-and-haskell.md b/content/md/gemfeed/2010-04-09-standard-ml-and-haskell.md index f43ef55a..5b9b38d8 100644 --- a/content/md/gemfeed/2010-04-09-standard-ml-and-haskell.md +++ b/content/md/gemfeed/2010-04-09-standard-ml-and-haskell.md @@ -4,7 +4,7 @@ I am currently looking into the functional programming language Standard ML (aka SML). The purpose is to refresh my functional programming skills and to learn something new too. Since I already know a little Haskell, could I do not help myself and I implemented the same exercises in Haskell too. -As you will see, SML and Haskell are very similar (at least when it comes to the basics). However, the syntax of Haskell is little bit more "advanced". Haskell utilises fewer keywords (e.g. no val, end, fun, fn ...). Haskell also allows to explicitly write down the function types. What I have been missing in SML so far is the so-called pattern guards. Although this is a very superficial comparison for now, so far I like Haskell more than SML. Nevertheless, I thought it would be fun to demonstrate a few simple functions of both languages to show off the similarities. +As you will see, SML and Haskell are very similar (at least when it comes to the basics). However, the syntax of Haskell is a bit more "advanced". Haskell utilizes fewer keywords (e.g. no val, end, fun, fn ...). Haskell also allows to explicitly write down the function types. What I have been missing in SML so far is the so-called pattern guards. Although this is a very superficial comparison for now, so far I like Haskell more than SML. Nevertheless, I thought it would be fun to demonstrate a few simple functions of both languages to show off the similarities. Haskell is also a "pure functional" programming language, whereas SML also makes explicit use of imperative concepts. I am by far not a specialist in either of these languages but here are a few functions implemented in both, SML and Haskell: diff --git a/content/md/gemfeed/2011-05-07-perl-daemon-service-framework.md b/content/md/gemfeed/2011-05-07-perl-daemon-service-framework.md index e23c2b8c..e47f407c 100644 --- a/content/md/gemfeed/2011-05-07-perl-daemon-service-framework.md +++ b/content/md/gemfeed/2011-05-07-perl-daemon-service-framework.md @@ -72,7 +72,7 @@ daemon.wd=./ ## Example -So lets start the daemon with a loop interval of 10 seconds: +So let's start the daemon with a loop interval of 10 seconds: ``` $ ./control keys | grep daemon.loopinterval @@ -138,7 +138,7 @@ sub do ($) { ### Your own module -Want to give it some better use? It's just a easy as: +Want to give it some better use? It's just as easy as: ``` cd ./lib/PerlDaemonModules/ @@ -148,7 +148,7 @@ Want to give it some better use? It's just a easy as: ./bin/perldaemon restart (or shortcurt ./control restart) ``` -Now watch `./log/perldaemon.log` closely. It is a good practise to test your modules in 'foreground mode' (see above how to do that). +Now watch `./log/perldaemon.log` closely. It is a good practice to test your modules in 'foreground mode' (see above how to do that). BTW: You can install as many modules within the same instance as desired. But they are run in sequential order (in future they can also run in parallel using several threads or processes). diff --git a/content/md/gemfeed/2021-05-15-buetow.org.sh-One-Bash-script-to-rule-it-all.draft.md b/content/md/gemfeed/2021-05-15-buetow.org.sh-One-Bash-script-to-rule-it-all.draft.md deleted file mode 100644 index e463d52d..00000000 --- a/content/md/gemfeed/2021-05-15-buetow.org.sh-One-Bash-script-to-rule-it-all.draft.md +++ /dev/null @@ -1,183 +0,0 @@ -# buetow.org.sh - One Bash script to rule it all - -> TODO: ADD WRITTEN BY AND CREATED AT BLABLA - -You might have read my previous blog post about entering the Geminispace. - -[Welcome to the Geminispace](./2021-04-24-welcome-to-the-geminispace) - -## Motivation - -Another benefit of using Gemini is that the Gemtext markup language is very easy to parse. As my site is dual hosted (Gemini+HTTP) I could in theory just write a shell script to deal with the conversion from Gemtext to HTML and not to rely on any external tools here. - -So I did exactly that, I wrote a Bash script which does the following: - -- Converts all Gemtext (*.gmi) files to HTML files -- Generates a Gemtext atom.xml feed for my blog posts -- Generates a HTML atom.xml feed of my blog posts - -I could have done all of that with a more powerful language than Bash (such as Perl, Ruby, Go...), but I didn't. The purpose of this exercise was to challenge what I can do with a "simple" Bash script and also to learn new things. - -``` - o .,<>., o - |\/\/\/\/| - '========' - (_ SSSSSSs - )a'`SSSSSs - /_ SSSSSS - .=## SSSSS - .#### SSSSs - ###::::SSSSS - .;:::""""SSS - .:;:' . . \\ - .::/ ' .'| - .::( . | - :::) \ - /\( / - /) ( | - .' \ . ./ / - _-' |\ . | - _..--.. . /"---\ | ` | . | - -=====================,' _ \=(*#(7.#####() | `/_.. , ( - _.-''``';'-''-) ,. \ ' '+/// | .'/ \ ``-.) \ - ,' _.- (( `-' `._\ `` \_/_.' ) /`-._ ) | - ,'\ ,' _.'.`:-. \.-' / <_L )" | - _/ `._,' ,')`; `-'`' | L / / - / `. ,' ,|_/ / \ ( <_-' \ - \ / `./ ' / /,' \ /|` `. | - )\ /`._ ,'`._.-\ |) \' - / `.' )-'.-,' )__) |\ `| - : /`. `.._(--.`':`':/ \ ) \ \ - |::::\ ,'/::;-)) / ( )`. | - ||::::: . .::': :`-( |/ . | - ||::::| . :| |==[]=: . - \ - |||:::| : || : | | /\ ` | - ___ ___ '|;:::| | |' \=[]=| / \ \ -| /_ ||``|||::::: | ; | | | \_.'\_ `-. -: \_``[]--[]|::::'\_;' )-'..`._ .-'\``:: ` . \ - \___.>`''-.||:.__,' SSt |_______`> <_____:::. . . \ _/ - `+a:f:......jrei''' -``` - -## W3C validator says all good -# -All generated HTML and Atom files pass the W3C validation. It is crazy that generating the Atom feed with valid XHTML content body for each blog posts was the most difficult part to implement in Bash. These formats are the reason why I decided to use Gemini as the primary protocol in the first place. However, Ironically I spent a couple of hours to get the XHTML and web Atoom feed working. To be fair, the Atom feed also works with Gemini. - -## Meta files for atom feed generation - -## Not without sed and grep and cut - -Soon I realised that I didn't want to go without a bit of grep and sed and cut. Regular expression matchings and simple string substitution tasks can be done in pure Bash but in my own opinion grep+sed are more powerful and easier to use (as I am used to these anyway). I managed not to use any AWK though. - -### Grepping - -I could use Bash's built-in regular expression matching engine here, but I am used to the grep pattern syntax, that's why I decided to do it this way: -``` -if grep -E -q "$IMAGE_PATTERN" <<< "$link"; then - html::img "$link" "$descr" - return -fi -``` - -### Sed-ing - -Sed comes in very handy for things like fixing HTML block text by replacing the lower than "<" and larger than ">" symbols with their corresponding HTML codes with one single command : - -``` -TODO: UPDATE SNIPPET echo "$line" | sed 's|<|\<|g; s|>|\>|g' -``` - -Sed is also useful in the following example, where the script checks whether the newly generated Atom feed file has changed compared to the previous version or not: - -``` -if ! diff -u <(sed 3d "$atom_file.tmp") <(sed 3d "$atom_file"); then - ... -else - ... -fi -``` - -### Cut-ing - -## Bash Modules for better structure - -I separated the script into different section; you could call them modules. For example, all functions dealing with the Atom feed are prefixed with atomfeed::, all functions dealing with HTML are prefixed with html:: and so on. - -As of writing this the script has the following modules and module functions: - -``` -TODO: UPDATE SNIPPET -❯ grep '::.* ()' buetow.org.sh -assert::equals () { -atom::meta () { -atom::generate () { -html::paragraph () { -html::heading () { -html::quote () { -html::img () { -html::link () { -html::gemini2html () { -html::generate () { -html::test () { -main::help () { -``` - -## Declaring all variables - -Many Bash scripts out in the wild don't have their variables declared, which leads to bad surprises as the default behaviour is that an undeclared variable is automatically a global variable once in use. So the best practise is to always declare a variable with one of the keywords "delcare", "readonly" or "local". - -Whole numbers can also have the option "-i", e.g. "declare -i num=52" and read only variables can be either declared via "readonly" or "rdeclare -r" or "local -r". Function local variables can also be declared with the "local" keyword. - -This is an example from the Atom module, where all variables are local to the function. I also make use of the "assign-then-shift"-pattern which goes like this: "local -r var1=$1; shift; local -r var2=$1; shift". The idea is that you only use "$1" to assign function arguments to named (better readable) local function variables. You will never have to bother about "$2" or above. That's is very useful when you constantly refactor your code and remove or add function arguments. It's something what I picked up from a colleague (a purely Bash wizard) some time ago: - -``` -atomfeed::meta () { - local -r now="$1"; shift - local -r gmi_file_path="$1"; shift - ... -} -``` - -## Unit tests - -Especially the Gemtext to HTML conversion part is an excellent use case for unit testing. There are unit tests for various Gemtext to HTML conversions (e.g. A header, paragraph, link, quote ...). My small unit test framework only consists of the test::assert() function. - -Forces to think creatively and to keep features fairly simple (good things) - -## De-facto templates - -## It's a static website generator - -Generate statically on my laptop and commit all statically generated files to fit. Can also preview locally. - -A lot of bash tricks - -## Config file - -## Learnings from ShellCheck - -ShellSheck: Not happy with all recommentations but most, e.g. read -r, quotes, etc. - -### While-read loops - -Specify -r - -### Warnings about variables not quoted - -### if cmd; then - -## The result(s) - -### Gemtext via Gemini protocol - -[gemini://buetow.org - The original Gemini capsule ](gemini://buetow.org) -[gemini://buetow.org/gemfeed/ - The Gemfeed](gemini://buetow.org/gemfeed/) -[gemini://buetow.org/gemfeed/atom.xml - The Atom feed](gemini://buetow.org/gemfeed/atom.xml) - -### XHTML via HTTP protocol - -[https://buetow.org - The original Gemini capsule ](https://buetow.org) -[https://buetow.org/gemfeed/ - The Gemfeed](https://buetow.org/gemfeed/) -[https://buetow.org/gemfeed/atom.xml - The Atom feed](https://buetow.org/gemfeed/atom.xml) - -TODO: ADD GO BACK LINK diff --git a/content/md/gemfeed/2021-05-15-buetow.org.sh-one-bash-script-to-rule-it-all.draft.md b/content/md/gemfeed/2021-05-15-buetow.org.sh-one-bash-script-to-rule-it-all.draft.md new file mode 100644 index 00000000..e463d52d --- /dev/null +++ b/content/md/gemfeed/2021-05-15-buetow.org.sh-one-bash-script-to-rule-it-all.draft.md @@ -0,0 +1,183 @@ +# buetow.org.sh - One Bash script to rule it all + +> TODO: ADD WRITTEN BY AND CREATED AT BLABLA + +You might have read my previous blog post about entering the Geminispace. + +[Welcome to the Geminispace](./2021-04-24-welcome-to-the-geminispace) + +## Motivation + +Another benefit of using Gemini is that the Gemtext markup language is very easy to parse. As my site is dual hosted (Gemini+HTTP) I could in theory just write a shell script to deal with the conversion from Gemtext to HTML and not to rely on any external tools here. + +So I did exactly that, I wrote a Bash script which does the following: + +- Converts all Gemtext (*.gmi) files to HTML files +- Generates a Gemtext atom.xml feed for my blog posts +- Generates a HTML atom.xml feed of my blog posts + +I could have done all of that with a more powerful language than Bash (such as Perl, Ruby, Go...), but I didn't. The purpose of this exercise was to challenge what I can do with a "simple" Bash script and also to learn new things. + +``` + o .,<>., o + |\/\/\/\/| + '========' + (_ SSSSSSs + )a'`SSSSSs + /_ SSSSSS + .=## SSSSS + .#### SSSSs + ###::::SSSSS + .;:::""""SSS + .:;:' . . \\ + .::/ ' .'| + .::( . | + :::) \ + /\( / + /) ( | + .' \ . ./ / + _-' |\ . | + _..--.. . /"---\ | ` | . | + -=====================,' _ \=(*#(7.#####() | `/_.. , ( + _.-''``';'-''-) ,. \ ' '+/// | .'/ \ ``-.) \ + ,' _.- (( `-' `._\ `` \_/_.' ) /`-._ ) | + ,'\ ,' _.'.`:-. \.-' / <_L )" | + _/ `._,' ,')`; `-'`' | L / / + / `. ,' ,|_/ / \ ( <_-' \ + \ / `./ ' / /,' \ /|` `. | + )\ /`._ ,'`._.-\ |) \' + / `.' )-'.-,' )__) |\ `| + : /`. `.._(--.`':`':/ \ ) \ \ + |::::\ ,'/::;-)) / ( )`. | + ||::::: . .::': :`-( |/ . | + ||::::| . :| |==[]=: . - \ + |||:::| : || : | | /\ ` | + ___ ___ '|;:::| | |' \=[]=| / \ \ +| /_ ||``|||::::: | ; | | | \_.'\_ `-. +: \_``[]--[]|::::'\_;' )-'..`._ .-'\``:: ` . \ + \___.>`''-.||:.__,' SSt |_______`> <_____:::. . . \ _/ + `+a:f:......jrei''' +``` + +## W3C validator says all good +# +All generated HTML and Atom files pass the W3C validation. It is crazy that generating the Atom feed with valid XHTML content body for each blog posts was the most difficult part to implement in Bash. These formats are the reason why I decided to use Gemini as the primary protocol in the first place. However, Ironically I spent a couple of hours to get the XHTML and web Atoom feed working. To be fair, the Atom feed also works with Gemini. + +## Meta files for atom feed generation + +## Not without sed and grep and cut + +Soon I realised that I didn't want to go without a bit of grep and sed and cut. Regular expression matchings and simple string substitution tasks can be done in pure Bash but in my own opinion grep+sed are more powerful and easier to use (as I am used to these anyway). I managed not to use any AWK though. + +### Grepping + +I could use Bash's built-in regular expression matching engine here, but I am used to the grep pattern syntax, that's why I decided to do it this way: +``` +if grep -E -q "$IMAGE_PATTERN" <<< "$link"; then + html::img "$link" "$descr" + return +fi +``` + +### Sed-ing + +Sed comes in very handy for things like fixing HTML block text by replacing the lower than "<" and larger than ">" symbols with their corresponding HTML codes with one single command : + +``` +TODO: UPDATE SNIPPET echo "$line" | sed 's|<|\<|g; s|>|\>|g' +``` + +Sed is also useful in the following example, where the script checks whether the newly generated Atom feed file has changed compared to the previous version or not: + +``` +if ! diff -u <(sed 3d "$atom_file.tmp") <(sed 3d "$atom_file"); then + ... +else + ... +fi +``` + +### Cut-ing + +## Bash Modules for better structure + +I separated the script into different section; you could call them modules. For example, all functions dealing with the Atom feed are prefixed with atomfeed::, all functions dealing with HTML are prefixed with html:: and so on. + +As of writing this the script has the following modules and module functions: + +``` +TODO: UPDATE SNIPPET +❯ grep '::.* ()' buetow.org.sh +assert::equals () { +atom::meta () { +atom::generate () { +html::paragraph () { +html::heading () { +html::quote () { +html::img () { +html::link () { +html::gemini2html () { +html::generate () { +html::test () { +main::help () { +``` + +## Declaring all variables + +Many Bash scripts out in the wild don't have their variables declared, which leads to bad surprises as the default behaviour is that an undeclared variable is automatically a global variable once in use. So the best practise is to always declare a variable with one of the keywords "delcare", "readonly" or "local". + +Whole numbers can also have the option "-i", e.g. "declare -i num=52" and read only variables can be either declared via "readonly" or "rdeclare -r" or "local -r". Function local variables can also be declared with the "local" keyword. + +This is an example from the Atom module, where all variables are local to the function. I also make use of the "assign-then-shift"-pattern which goes like this: "local -r var1=$1; shift; local -r var2=$1; shift". The idea is that you only use "$1" to assign function arguments to named (better readable) local function variables. You will never have to bother about "$2" or above. That's is very useful when you constantly refactor your code and remove or add function arguments. It's something what I picked up from a colleague (a purely Bash wizard) some time ago: + +``` +atomfeed::meta () { + local -r now="$1"; shift + local -r gmi_file_path="$1"; shift + ... +} +``` + +## Unit tests + +Especially the Gemtext to HTML conversion part is an excellent use case for unit testing. There are unit tests for various Gemtext to HTML conversions (e.g. A header, paragraph, link, quote ...). My small unit test framework only consists of the test::assert() function. + +Forces to think creatively and to keep features fairly simple (good things) + +## De-facto templates + +## It's a static website generator + +Generate statically on my laptop and commit all statically generated files to fit. Can also preview locally. + +A lot of bash tricks + +## Config file + +## Learnings from ShellCheck + +ShellSheck: Not happy with all recommentations but most, e.g. read -r, quotes, etc. + +### While-read loops + +Specify -r + +### Warnings about variables not quoted + +### if cmd; then + +## The result(s) + +### Gemtext via Gemini protocol + +[gemini://buetow.org - The original Gemini capsule ](gemini://buetow.org) +[gemini://buetow.org/gemfeed/ - The Gemfeed](gemini://buetow.org/gemfeed/) +[gemini://buetow.org/gemfeed/atom.xml - The Atom feed](gemini://buetow.org/gemfeed/atom.xml) + +### XHTML via HTTP protocol + +[https://buetow.org - The original Gemini capsule ](https://buetow.org) +[https://buetow.org/gemfeed/ - The Gemfeed](https://buetow.org/gemfeed/) +[https://buetow.org/gemfeed/atom.xml - The Atom feed](https://buetow.org/gemfeed/atom.xml) + +TODO: ADD GO BACK LINK diff --git a/content/md/gemfeed/2021-05-15-personal-bash-coding-style-guide.draft.md b/content/md/gemfeed/2021-05-15-personal-bash-coding-style-guide.draft.md new file mode 100644 index 00000000..bd21e74b --- /dev/null +++ b/content/md/gemfeed/2021-05-15-personal-bash-coding-style-guide.draft.md @@ -0,0 +1,67 @@ +# Personal Bash coding style guide + +``` + .---------------------------. + /,--..---..---..---..---..--. `. + //___||___||___||___||___||___\_| + [j__ ######################## [_| + \============================| + .==| |"""||"""||"""||"""| |"""|| +/======"---""---""---""---"=| =|| +|____ []* ____ | ==|| +// \\ // \\ |===|| hjw +"\__/"---------------"\__/"-+---+' +``` + +> Written by Paul Buetow 2021-15-21 + +Lately, I have been polishing and writing a lot of Bash code. Not that I never wrote a lot of Bash, but now as I also looked through the "Google Shell Style Guide" I thought it is time to also write my thoughts on that. I agree to that guide in most, but not in all points. + +[Gogle Shell Style Guide](https://google.github.io/styleguide/shellguide.html) + +I also highly recommend to have a read through the "Advanced Bash-Scripting Guide" (which is not from Google but written by Mendel Cooper). I learn something new every time I have a look at it. + +[Advanced Bash-Scripting Guide](https://tldp.org/LDP/abs/html/) + +## My modifications + +These are my personal modifications of the Google Guide. + +### 2 space soft-tabs indentation + +I know there have been many tab and soft-tab wars on this planet. Google recommends to use 2 space soft-tabs. + +My own reality is I don't really care if I use 2 or 4 space indentations. I agree however that tabs should not be used. I personally tend to use 4 space soft-tabs as that's currently how my personal Vim is configured for any programming languages. What matters most though is consistency within the same script/project. + +Google also recommends to limit line length to 80 characters. For some people that seem's to be an ancient habit from the 80's, where all computer terminals couldn't display longer lines. But I think that the 80 character mark is still a good practise at least for shell scripts. For example I am often writing code on a Microsoft Go Tablet PC (running Linux of course) and it comes in very handy if the lines are not too long due to the relatively small display on the device. + +I hit the 80 character line length quicker with the 4 spaces, but that makes me refactor the Bash code more aggressively which is actually a good thing. + +### Breaking long pipes + +### Quoting your variables + +### Prefer internal over external commands + +## My additions + +### Use of 'yes' and 'no' + +### Non-evil alternative to variable assignments via eval + +### Prefer pipes over arrays for list processing + +## Learned + +### Strucking me + +### PIPESTATUS + + + + + + +E-Mail me your thoughts at comments@mx.buetow.org! + +[Go back to the main site](../) -- cgit v1.2.3