Muchang Bahng

Linux & Bash


Contents
  1. Intro to Linux
  2. Vim
  3. Bash Scripting

Introduction to Linux

[Hide]

We will use Ubuntu 22.04.
Formattng Hard Drives
Use GParted.

Vim

[Hide]

There are many different installations of Vim, but we will use vim-nox, which provides support for scripting with various languages.
sudo apt install vim-nox
apt show vim-nox
Now we should be able to go into our shell and type vim to open the text editor. What shows up is a buffer, which is just some free memory that we can type in. This can be a new file that is not saved or an existing file that we are editing. When opening Vim, we are in command mode, which allows to run the following commands:
  1. Quit the editor :q or quit without saving :q!
  2. Go into insert mode at the beginning i or at the end SHIFT + A
  3. Get out of insert mode ESC
  4. Save the file :w test.txt, where w stands for "write" and test.txt is the file name
  5. If you have opened an existing file, then you can save it simply by typing :w
  6. To undo your changes, type u
  7. Delete the line you are on dd
Furthermore, if you are in command mode and you type :, you can press the up arrow to get your previous commands.
Arrow Keys
In command mode, we can use the arrow keys to navigate around but we can just as well do that with the H, J, K, L keys as well to save the trouble of having to reach down to the arrow keys.

Bash Scripting

[Hide]

Learning bash scripting allows you to automate tasks that you would normally do in a terminal in a script. We just need to open a text editor and a bash script should always start with a #!/bin/bash a the top, known as a shebang. From this we can enter in the commands that we would type as below.
#!/bin/bash 

ls 
pwd
echo "Hello World!"
Now we can save it as myscript.sh (the suffix is not really needed if we have the shebang, but for clarity). Before we can run it, we must turn it into an executable with the command
chmod +x myscript.sh 
By going into the working directory and running ls --color, we can color code all the files/directories, where green stands for executables and blue are directories. Now we can run it by
./myscript.sh
Variables
We can set variables directly in the terminal. Note that there should not be spaces in between the equal sign and words. Furthermore, when we try to echo a variable, we must use a dollar sign to print the contents of it. If we do not use it, then it will literally print the name of the variable.
(base) mbahng@xps-15-9500:~/Desktop$ myName="Muchang"
(base) mbahng@xps-15-9500:~/Desktop$ echo $myName
Muchang
(base) mbahng@xps-15-9500:~/Desktop$ echo myName
myName
We must have the dollar sign since there are no key words in bash. Unlike Python, where certain words like if, else, while, etc. are reserved for certain commands and therefore cannot be used as variables, we don't have this control in bash, so we need the $. Also, if we declare a variable, it is tied to the session, so closing the terminal will delete all references. Now we can simply apply this to a bash script. Below, we want to show one more property that distinguishes single quotes and double quotes. We want to use double quotes since single quotes will output as raw strings.
#!/bin/bash 

myName="Muchang" 
myAge="21" 

echo "Hello, my name is $myName."
echo 'Hello, my name is $myName.'
echo "I am $myAge years old."
and running it gives
(base) mbahng@xps-15-9500:~/Desktop$ ./myscript.sh 
Hello, my name is Muchang.
Hello, my name is $myName.
I am 21 years old.  
Now to set the variable equal to the output of a command, like pwd or ls, we can just store it inside a paranthesis.
(base) mbahng@xps-15-9500:~/Desktop$ files=$(pwd)
(base) mbahng@xps-15-9500:~/Desktop$ echo $files
/home/mbahng/Desktop
We can use this in combination with the date command to create maybe a script that greets us and returns the current time:
#!/bin/bash

myName="Muchang"

echo "Hello, $myName."
echo "Today's date is $(date)"

(base) mbahng@xps-15-9500:~/Desktop$ ./myscript.sh 
Hello, Muchang.
Today's date is Thu Jun 29 03:32:13 PM EDT 2023
There are special types of variables, called environment variables, which are all in uppercase. Due to this reason, it is important to conventionally keep your own variables to not be all uppercase, as they may get confused with the environment variables. We can view all of them with the env command.
(base) mbahng@xps-15-9500:~/Desktop$ env
SHELL=/bin/bash
SESSION_MANAGER=local/xps-15-9500:@/tmp/.ICE-unix/80970,unix/xps-15-9500:/tmp/.ICE-unix/80970
QT_ACCESSIBILITY=1
COLORTERM=truecolor
XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/etc/xdg
SSH_AGENT_LAUNCHER=gnome-keyring
XDG_MENU_PREFIX=gnome-
...
These are always initialized and can be accesssed and so we do not need to manually reference them.
(base) mbahng@xps-15-9500:~/Desktop$ echo $HOME 
/home/mbahng
(base) mbahng@xps-15-9500:~/Desktop$ echo $USER
mbahng
Basic Math
To do basic math in Python, we just needed to type in 30 + 10 in the Python shell. However, in Bash, we need to use the evaluate expression command, abbreviated expr, where we can do addition, subtraction, multiplication (which needs the escape character since * is a wildcard), and integer division.
(base) mbahng@xps-15-9500:~$ expr 30 + 10
40
(base) mbahng@xps-15-9500:~$ expr 30 - 10 
20
(base) mbahng@xps-15-9500:~$ expr 30 \* 10
300
(base) mbahng@xps-15-9500:~$ expr 30 / 10
3
(base) mbahng@xps-15-9500:~$ expr 30 / 8
3
Note that the spaces between the operation and the numbers is important.
(base) mbahng@xps-15-9500:~$ expr 30+10
30+10  
Again, we can store these integers in variables and operate on them.
(base) mbahng@xps-15-9500:~$ myNum1=100
(base) mbahng@xps-15-9500:~$ echo $myNum1
100
(base) mbahng@xps-15-9500:~$ expr $myNum1 + 50
150
(base) mbahng@xps-15-9500:~$ myNum2=88
(base) mbahng@xps-15-9500:~$ expr $myNum1 - $myNum2
12  
Conditionals
The syntax for a conditional is the following, where the conditionals are within square brackets, and we must always close the if statement with a fi.
#!/bin/bash

myNum=200

if [ $myNum -eq 200 ]
then
    echo "The condition is true." 
else 
    echo "The variable does not equal 200."
fi
Let us clarify some more math operators: To check if there exists a file called myfile within a directory, we can write
#!/bin/bash

if [ -f ~/myfile ]
then
    echo "The file exists" 
else
    echo "The file does not exist" 
fi
We can do the same for directories by simply replacing the -f with a -d.
Exit Codes
An exit code basically tells us whether our commands in the termainal ran or encountered some error. Up until now, we can make our best judgement in deciding whether our command actually ran successfully (that is, if there was no error). To properly diagonse this, we can output the contents of the ? variable, which actually tells us whether the input command was a success or failure. The variable is initialized every time we enter in a command.
(base) mbahng@xps-15-9500:~/Desktop$ ls -l /misc
ls: cannot access '/misc': No such file or directory
(base) mbahng@xps-15-9500:~/Desktop$ echo $?
2
Basically, an exit code of 0 means that the command was successful, and anything other than 0 means a failure. The reason we want these exit codes is that when we automate tasks, we want scripts to run based on the exit codes of our original scripts. That is, if we get an exit code of 0, then this may trigger another bash script that emails the system administrator to let them know that something was wrong. We can create an example script that installs a package using apt as such:
#!/bin/bash

package=htop 

sudo apt install package 

if [ $? -eq 0 ] 
then 
    echo "The installation of $package was successful."
    echo "The new command is available here:" 
    which $package 
else 
    echo "$package failed to install."
fi 
To manually force the exit code to be a certain number, we can do so as below. Note that since this is an exit code the script will end right at the line where we call exit. This is not like a break statement, where it breaks out of a loop to continue on the script. It literally terminates the script right here.
#!/bin/bash 

sudo apt install notexist 
exit 0 
Outputting in a File
We can also take all the outputs of whatever commands we ran and put them into a file with the >> symbol.
mbahng@xps-15-9500:~/Desktop$ apt list >> packages.txt
Loops
The syntax for a while loop is similar to a conditional, with square brackets. This prints out 1 through 10, with a 0.5 second timer in between.
#!/bin/bash 

myVar=1 

while [ $myVar -le 10 ] 
do 
    echo $myVar 

    # Increment by 1 
    myVar=$(( $myVar + 1))

    # Sleep for 0.5 seconds 
    sleep 0.5
done 
The syntax for a for loop within a range of number is:
#!/bin/bash 

for i in {1..10} 
do 
    echo $i 
    sleep 1 
done 

echo "This is outside of the for loop. "
We can also iterate over all files with a .log suffix in the logfiles directory and compresses them for using tar.
#!/bin/bash 

for file in logfiles/*.log 
do 
    tar -czvf $file.tar.gz $file
done
Storing Scripts for Convenient Execution
To conveniently execute your scripts, it is advised to put them in your /usr/local/bin and to remove the .sh suffix. There are two reasons for this: