diff --git a/.gitignore b/.gitignore index 1377554..23c0921 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.swp +tmp.* diff --git a/advanced/learning_bash_scripting.md b/advanced/learning_bash_scripting.md index b91b64c..822454d 100644 --- a/advanced/learning_bash_scripting.md +++ b/advanced/learning_bash_scripting.md @@ -351,7 +351,6 @@ waldek@metal:~$ # Coding challenge - Output system stats - Write a program that prints information about your computer such as: * the hostname @@ -410,6 +409,9 @@ hmmm, I don't know how to compare helloworld to supersecret waldek@metal:~$ ``` +We haven't learned how to *evaluate* values but if you're eager and quick you can try to figure it out yourself. +If not, no worries, we'll get to *conditional logic* soon enough. +
Spoiler warning! @@ -425,11 +427,32 @@ echo "hmmm, I don't know how to compare $pass to $my_pass"
- - ### `read` multiple variables -TODO +`read` can be used to unpack multiple values right on the spot! +By *unpacking* I mean that each value is separated by **white space**. +A demonstration can be seen below, plus the actual code right after. + +``` +waldek@debian:~$ bash test.sh +first and last name please: wouter gordts +hello mr gordts... +or may I call you wouter? +waldek@debian:~$ +``` + +``` +#!/bin/bash + +read -p "first and last name please: " first last +echo "hello mr $last..." +echo "or may I call you $first?" +``` + +#### Exercise - unpack values + +It is worth discovering what happens when you supply too many or to little values. +Please try this out! ## With command line arguments @@ -457,14 +480,6 @@ This variable represents the *first* argument on the command line. Knowing this, what would `$4` mean? Indeed, the *fourth* argument... -## From a file - -TODO - -## From a pipe - -TODO - # Coding Challenge - output the exact output below ``` @@ -900,14 +915,208 @@ fi +# Coding challenge - pipe or argument? + +Can you code me a script that depending on how it is called, with argument or via pipe, prints a different message? +Along these lines... + +``` +waldek@debian:~$ bash test.sh +No input was found on stdin, skipping! +No input given! +waldek@debian:~$ bash test.sh shopping.list +No input was found on stdin, skipping! +Filename specified: shopping.list +Doing things now.. +waldek@debian:~$ cat shopping.list | bash test.sh +Data was piped to this script! +waldek@debian:~$ +``` + +
+Spoiler warning! + +**It might take you some time but we've seen all the necessary building blocks!** + +
+Spoiler warning! + +```bash +#!/bin/bash + +if [ -p /dev/stdin ]; then + echo "Data was piped to this script!" +else + echo "No input was found on stdin, skipping!" + if [ -f "$1" ]; then + echo "Filename specified: ${1}" + echo "Doing things now.." + else + echo "No input given!" + fi +fi +``` + +
+ +
# Loops - A variety of ways to perform repetitive tasks. -[Ryan's tutorials](https://ryanstutorials.net/bash-scripting-tutorial/bash-loops.php) +Up until now all our scripts run from top to bottom, executing each line as they are read. +Most, if not all, programming languages offer some form of looping to **repeat** lines of code either based on a **condition** or for a predefined number of *items*. -Write a script that sets all you cpu's to a desired governor. +## `while` loop -Rename all files in a folder with an prefix or postfix. +```bash +#!/bin/bash + +counter=0 + +while [[ counter -lt 10 ]]; do + echo $counter + (( counter++ )) +done +``` + +### Read from a file with a `while` loop + +Below you can see I have two files, one is my *shopping list*, the other my script. +The script loops over each item I have to buy and prints me a verbose message. + +``` +waldek@debian:~$ cat shopping.list +6 eggs +1 bread +2 milk +4 pasta +waldek@debian:~$ bash test.sh shopping.list +you need to buy: 6 eggs +you need to buy: 1 bread +you need to buy: 2 milk +you need to buy: 4 pasta +waldek@debian:~$ +``` + +One way to do this is with a `while` loop. +The syntax is a follows. + +```bash +#!/bin/bash + +while read line; do + echo "you need to buy: $line" +done < $1 +``` + +The syntax is not what I would call *pretty* but it is quite effective. +The **file** `$1` is redirected **into** the `while` loop which performs a `read`. +**When** there are no more lines in the file, the condition **fails** and the loop exits. + +### Read from a pipe with a `while` loop + +We can use a *very* similar construct to read data from a pipe. +The utilisation is as follows. + +``` +waldek@debian:~$ cat shopping.list | ./test.sh +you need to buy: 6 eggs +you need to buy: 1 bread +you need to buy: 2 milk +you need to buy: 4 pasta +waldek@debian:~$ +``` + +And the code that does this as such. + +```bash +#!/bin/bash + +while IFS= read line; do + echo "you need to buy: $line" +done +``` + +What on earth is this `IFS=`? +I'm glad you [asked](https://unix.stackexchange.com/questions/184863/what-is-the-meaning-of-ifs-n-in-bash-scripting)! + +## `for` loop + +Ah, my favorite loop! +While the `while` loop runs as long as a condition is `true`, the `for` loop **iterates** over *items*. +The simplest way to visualize it would be as follows. +For each *friend* in my list of friends I'll say hello. + +``` +waldek@debian:~$ ./test.sh +these are my friends: adam camille alice bob steve +hello adam! +hello camille! +hello alice! +hello bob! +hello steve! +waldek@debian:~$ +``` + +The syntax to achieve this goes as follows. + +```bash +#!/bin/bash + +friends="adam camille alice bob steve" +echo "these are my friends: $friends" +for f in $friends; do + echo "hello $f!" +done +``` + +### Counter loops with `for` + +We can do a counter loop as well via a `for` loop. +An easy way to do this is by using the `seq` program. +Remember to read the `man seq` for more information. + +```bash +#!/bin/bash + +for number in $(seq 0 10); do + echo "number is $number" +done +``` + +### Finicky behaviour + +`bash` is not the prettiest language and the difference between single and double quotes can be a bit confusing. + +```bash +#!/bin/bash + +for animal in dog cat horse 'racing horse' whale; do + echo "$animal says: I'm an animal..." +done +``` + +Which gives the following output. + +``` +waldek@debian:~$ ./test.sh +dog says: I'm an animal... +cat says: I'm an animal... +horse says: I'm an animal... +racing horse says: I'm an animal... +whale says: I'm an animal... +waldek@debian:~$ +``` + +# Coding challenge - pipe or argument plus action! + +Can you expand the previous coding challenge, where you perform a conditional logic on the input of the script and actually *use* the incoming data? + +# Coding challenge - Rename files + +Rename all files from [this](../assets/simple_sort_01.tar.gz) file with an prefix or postfix. +Can you give the files that start with an **uppercase** letter a different pre or postfix? +Can you move the files with lowercase into a different folder? # Functions - Reuse code to make life easier. @@ -923,6 +1132,7 @@ Rename all files in a folder with an prefix or postfix. # User Interface - Make your scripts user friendly. +* `case` for command line arguments * [dialog tutorial](https://www.linuxjournal.com/article/2807) * [better dialog tutorial](https://linuxcommand.org/lc3_adv_dialog.php) * [Ryan's tutorials](https://ryanstutorials.net/bash-scripting-tutorial/bash-user-interfaces.php) diff --git a/assets/simple_sort_01.tar.gz b/assets/simple_sort_01.tar.gz new file mode 100644 index 0000000..b40951a Binary files /dev/null and b/assets/simple_sort_01.tar.gz differ