diff options
| author | Paul Buetow <paul@buetow.org> | 2021-11-26 09:46:43 +0000 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2021-11-26 09:46:43 +0000 |
| commit | 3960d95e3481787acd4799c995212353e40c7263 (patch) | |
| tree | 0e75e543618a58ea4213e442cf2656a3bc0a06a4 | |
| parent | 87141cac574b56b8b04df3eb03644c3e02589ca6 (diff) | |
more on this
| -rw-r--r-- | gemfeed/2021-11-21-bash-golfing.draft.gmi | 252 |
1 files changed, 192 insertions, 60 deletions
diff --git a/gemfeed/2021-11-21-bash-golfing.draft.gmi b/gemfeed/2021-11-21-bash-golfing.draft.gmi index a743bcb7..2293244f 100644 --- a/gemfeed/2021-11-21-bash-golfing.draft.gmi +++ b/gemfeed/2021-11-21-bash-golfing.draft.gmi @@ -2,7 +2,7 @@ > Written by Paul Buetow 2021-11-21 -This blog post is about some (mostly uncommon) bash tricks I came across in the past. +This blog post is about some random Bash tricks I came across in the past. It's a collection of smaller articles I wrote in an older blog of mine plus the translation from German into English plus some updates and additions. ## TCP/IP networking @@ -233,9 +233,9 @@ The "tar" command understands "-" too. This example tars up some local directory And this is yet another example of using "-", but this time using the "file" command: ``` -$ head -n 1 test.sh +$ head -n 1 grandmaster.sh #!/usr/bin/env bash -$ file - < <(head -n 1 test.sh) +$ file - < <(head -n 1 grandmaster.sh) /dev/stdin: a /usr/bin/env bash script, ASCII text executable ``` @@ -459,7 +459,7 @@ Bratwurst You can also override the default file descriptors, like demonstrated in this script: ``` -❯ cat test.sh +❯ cat grandmaster.sh #!/usr/bin/env bash # Write a file data-file containing two lines @@ -488,76 +488,208 @@ exec 0<&6 6<&- Let's execute it: ``` -❯ ./test.sh +❯ chmod 750 ./grandmaster.sh +❯ ./grandmaster.sh First line: Learn You a Haskell Second line: for Great Good ``` -## Here +## HERE -Wie in vielen anderen Skriptsprachen unterstützt auch die Bash sog. Here-Dokumente. Hier ein kleines -Beispiel: -pb@titania: $ cat END -> Hallo Welt -> it’s $(date) +We have touched HERE-documents and HERE-strings already in this post. Let's do some more examples. The following "cat" receives a multi line string from stdin. In this case the input multi line string is a HERE-document. As you can see, it also interpolates variables (in this case the output of "date" running in a sub-shell). + +``` +❯ cat <<END +> Hello World +> It’s $(date) +> END +Hello World +It's Fri 26 Nov 08:46:52 GMT 2021 +``` + +You can also write it this way, but that's less readable (it's good for an obfuscation contest): + +``` +❯ <<END cat +> Hello Universe +> It’s $(date) > END -Hallo Welt -it’s Fr 13. Mai 11:07:36 CEST 2011 -pb@titania: $ -Neben kennt die Bash auch den Operator <. Während -sog. Here-Strings verwendet. -für Here-Dokumente reserviert ist, wird < für -So könnte man ohne einen Here-String prüfen, ob eine Variable einen bestimmte Substring enthält: -VAR=foo; if echo ” $VAR” | grep -q foo; then echo \ $VAR contains foo; fi -Und so mit Here-String: -if grep -q foo < ” $VAR”; then echo \ $VAR contains foo; fi -Wie unschwer zu erkennen ist spart man sich hier einiges an Tipparbeit (ein echo und eine Pipe weniger). -(PS: Das könnte man auch ohne grep, nämlich mit Bash Regexp überprüfen, aber dazu evtl. später mehr). - -Here-Strings können auch in Kombination mit read angewandt werden: - -pb@titania: -pb@titania: -pb@titania: +Hello Universe +It's Fri 26 Nov 08:47:32 GMT 2021 +``` + +Besides of an HERE-document there is also a so-called HERE-string. Besides of... + +``` +❯ declare VAR=foo +❯ if echo "$VAR" | grep -q foo; then +> echo '$VAR ontains foo' +> fi +$VAR ontains foo +``` + +you can use a HERE-string like that: + +``` +❯ if grep -q foo <<< "$VAR"; then +> echo '$VAR contains foo' +> fi +$VAR contains foo +``` + +or even shorter: + +``` +❯ grep -q foo <<< "$VAR" && echo '$VAR contains foo' +$VAR contains foo +``` + +You could also use a Bash regex to accomplish the same thing, but the point of the examples so far is to demonstrate HERE-{documents,strings}: + +``` +❯ if [[ "$VAR" =~ foo ]]; then echo yay; fi +yay +``` + +You can also use it with "read", e.g. read a sentence into an array of words: + +``` +❯ 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 -pb@titania: -you -pb@titania: -a -$ dumdidumstring=”Learn you a Haskell for Great Good” -$ read -a words < ” $dumdidumstring” -$ echo $ {words[0] } -$ echo $ {words[1] } -$ echo $ {words[2] } -Das -a bei read bezweckt, dass words aus dem Here-String als Array befüllt werden soll. -Mittels Here-String kann man auch eine Zeile einer Textdatei prependen: -pb@titania:/tmp $ echo for Great Good > file.txt -pb@titania:/tmp $ cat - file.txt <”Learn you a Haskell” -Learn you a Haskell -for Great Good -Das hat allerdings den Nachteil, dass man das Ergebnis zuerst in eine temporäre Datei oder Variable schreiben -muss, bevor man die Originaldatei file.txt überschreibt. Ansonsten kommt es zu einem Fehler: -pb@titania:/tmp $ cat - file.txt <”Learn you a Haskell” > file.txt -cat: file.txt: Eingabedatei ist Ausgabedatei -Natürlich wäre hierbei sed sowieso das bessere Tool der Wahl: - -pb@titania:/tmp $ echo for great Good > file.txt -pb@titania:/tmp $ sed -i -e ’1i\ -Learn you a Haskell’ file.txt -pb@titania:/tmp $ cat file.txt -Learn you a Haskell -for great Good -pb@titania:/tmp $ +❯ echo ${words[3]} +Golang +``` -## xargs +The following is good for an obfuscation contest too: + +``` +❯ echo 'I like Perl too' > perllove.txt +❯ cat - perllove.txt <<< "$dumdidumstring" +Learn you a Golang for Great Good +I like Perl too +``` ## RANDOM -## -x and set -x +Random is a special builtin variable containing a pseudo random number each time it's used. + +``` +❯ echo $RANDOM +11811 +❯ echo $RANDOM +14997 +❯ echo $RANDOM +9104 +❯ echo $RANDOM +26750 +``` + +That's very useful if you want to randomly delay the execution of your scripts when you run it on many servers concurrently just to spread the server load better. + +Let's say you want to introduce a random delay of 1 minute you can do: + +``` +❯ cat ./calc_answer_to_ultimate_question_in_life.sh +#!/usr/bin/env bash + +declare -i MAX_DELAY=60 + +random_delay () { + declare -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. +} + +main + +❯ ./calc_answer_to_ultimate_question_in_life.sh +Delaying script execution for 42 seconds... +Continuing script execution... +``` + +## set -x and set -e and pipefile + +In my opinion, -x and -e and pipefile are the most useful Bash options. Let's have a look at them one after another. + +### -x + +-x prints commands and their arguments as they are executed. This helps developing and debugging your Bash code: + +``` +❯ 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 +``` + +However, you need to set -x also for the sub-shell in oder to print out what is happening: + +``` +❯ num=12; echo "Square of $num is $(set -x;square $num)" ++ num=12 +++ set -x +++ square 12 +++ local -i num=12 +++ echo 144 ++ echo 'Square of 12 is 144' +Square of 12 is 144 +❯ +``` + +You can also use the option like this, if helped me personally a lot: + +``` +❯ bash -x ./half_broken_script_to_be_debugged.sh +``` + +Let's do that on one of the example scripts we used earlier: + +``` +❯ 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 +❯ +``` + +## xargs ## More -Reference to my bash coding style guide. +Have also a look at my personal Bash coding style guide: + +=> ./2021-05-16-personal-bash-coding-style-guide.gmi Personal Bash coding style guide + +TODO: Also link from my Bash coding style guide to this article. E-Mail me your thoughts at comments@mx.buetow.org! |
