completes some more bash scripting

This commit is contained in:
waldek 2022-05-23 15:20:56 +02:00
parent 74fa7c957a
commit 83d38d2105
3 changed files with 226 additions and 15 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
*.swp
tmp.*

View File

@ -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.
<details>
<summary>Spoiler warning!</summary>
@ -425,11 +427,32 @@ echo "hmmm, I don't know how to compare $pass to $my_pass"
</details>
### `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
</details>
# 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:~$
```
<details>
<summary>Spoiler warning!</summary>
**It might take you some time but we've seen all the necessary building blocks!**
<details>
<summary>Spoiler warning!</summary>
```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
```
</details>
</details>
# 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)

Binary file not shown.