That’s it. We are done with our Linux journey. I hope it’s been a joyful ride. I hope you have confidence that you have a firm grasp of the basics of Linux and if you need to explore any additional parts of Linux you will have a great sense of where it fits in into the bigger picture.
May the force of the penguin be with you from this point on!
Thank you for reading and I hope you enjoyed the ride!
There are things I never used in shell scripting, such as sed, awk, basename etc. Since shell scripts are composed mostly of commands, the commands I never used on the command line I have never used in shell scripts as well.
I covered everything I deemed important for shell scripting, but if you encounter something you don’t understand, feel free to use Google or reference (Shotts, 2019). Although a caveat: (Shotts, 2019) seems to take the stance of “show a whole lot of features of shell scripting” where I am more biased towards “learn only the essentials of shell scripting and use other programming languages for activities other than file manipulation”. Just a difference to keep in mind.
Thank you for reading!
References
Shotts, W. (2019). The Linux Command Line, Fifth Internet Edition. Retrieved from http://linuxcommand.org/tlcl.php. Part 4 – Writing Shell Scripts
Fixing errors, also known as troubleshooting, is a process or removing errors from your bash script.
If you adhere to the rule which I laid out before, which was “Use single quotes to enclose values unless you have a concrete reason not to”, you will be fine most of the time. For the times when you are not fine, literally copy and paste the error message you’re getting into Google and you will get some suggestions.
There is a finely written piece on this in (Shotts, 2019), which again, let me remind you, is free on the World Wide Web, so go read it.
Thank you for reading!
References
Shotts, W. (2019). The Linux Command Line, Fifth Internet Edition. Retrieved from http://linuxcommand.org/tlcl.php. Pages 454-467
You can read user input in shell scripts. (Ward, 2014)
Here is an example of a script which reads user input:
#!/bin/bash
read name
echo "My name is $name"
Notice how I used the double quotes to make the shell expand my variable. My variable, by the way, is called name. read name prompts the user for input and when the user inputs the information (and presses Enter), that input is stored in the variable named name.
As you already know, you can read user input through arguments that you pass to your shell script. I don’t know which way is the better way and which way is more idiomatic to the shell, but I’d opt for passing values as arguments to the script and then doing checks on the arguments at the beginning of the script. You can also do these checks after reading something in a variable (such as “Is the string that the user inputted empty?”), but I think that doing these checks after each read is tedious; much better to do them at the beginning of the script. Again, not certain which way is idiomatic to the shell and both exist so both must be fine, but I am unsure.
Hope you learned something useful!
References
Ward, B. (2014). How Linux Works: What Every Superuser Should Know (2nd ed.). No Starch Press. Page 269
You can take a result of a command and store it in a variable or use the result of that first command as an argument for another command. This is called command substitution. (Ward, 2014)
Here is an example of command substitution in a sample script:
#!/bin/bash
LINES=$(grep 'a' aba.txt)
for word in $LINES
do
echo $word
done
We first take every line that has the character a in the file aba.txt and then we store it in the variable LINES. Then we iterate over each word in the variable LINES and we print it. Why does LINES contain words, not lines? It contains lines indeed, but words that make up those lines are separated by a space (you can see so yourself by putting echo $LINES just before the for loop) and since each space is interpreted as a delimiter in a sequence, we get individual words.
while and until loops are used for iteration, the same as for loops. However, I won’t teach you these. Why? Because, as (Ward, 2014) says, if you ever need a while loop (or an until loop), it’s a good time to move to another programming language. I agree.
I will tell you that (“Bash While Loop Examples,” n.d.) and a Google search will teach you, if you really must use them. But again, I will repeat myself: If you need to use a while or an until loop, switch to another programming language.
What just happened? The variable i first took on the value of 1 (the first element in the sequence). Then it echoed its value. Then variable i took the next value in the sequence (the value after the value it currently had). So i was 2. Then 2 got outputted – and so on until the end of the sequence.
You can specify numerical sequences more easily (the above one could have been written as {1..5}) and you can iterate over other sequences (not just numbers, but other things – files for example). I leave you to consult the reference and Google for some further examples.
Today let’s talk about the case statement. case statement is used to replace a lot of elif statements. Here is our entire script with the same functionality it had before, rewritten using a case statement:
#!/bin/bash
case $1 in
'Hello')
echo 'Hello back to you!'
;;
'Hi')
echo 'Hi!'
;;
*)
echo 'You are rude.'
;;
esac
Here is how the case statement works:
You tell case which argument you are testing (more specifically, pattern matching) – we are testing the argument passed to the script in the first position ($1)
case goes through the list of patterns (each pattern ends in a )) and if it finds a matching pattern, the code between the ) and the ;; is executed and then it skips to esac
esac denotes the end of the case statement
The case statement does not evaluate any exit codes, it just matches patterns.
Here are some things to note: (Ward, 2014)
multiple strings can be matched with | – if I put ‘Hi!’|’Hi’ I would match both “Hi!” and “Hi” and that line would look like 'Hi!'| ‘Hi’)
* matches a case which is unmatched by any other case
Hope you found this useful!
References
Ward, B. (2014). How Linux Works: What Every Superuser Should Know (2nd ed.). No Starch Press. Pages 261-262
We talked about logical operators (&& (and) and || (or)) and got to understand how they work. You can also use them in tests.
If you use &&, then if the first test is not successful, its exit code is used for the if statement and if the first test is successful, then the exit code of the second test is used for the if statement. If you use ||, if the first test is not successful, the second test’s exit code is used as the exit code for the if statement and if the first test is successful, the first test’s exit code is used as the exit code for the if statement. (Ward, 2014)
For example, you can write:
if [ “$1” = ‘Hi’ ] || [ “$1” = ‘Hello’ ]
if you were to test if the first argument is either “Hi” or “Hello”.
Think of it like this: && says “Both of the conditions have to be true” while || says “Only one of the conditions must be true”. This holds because only the exit value of 0 is used to indicate success. Re-read the second paragraph and make sure you understand this.
You can combine more than just two conditions with logical operators.
Hope you learned something useful!
References
Ward, B. (2014). How Linux Works: What Every Superuser Should Know (2nd ed.). No Starch Press. Page 258