mirror of
https://codeberg.org/Mo8it/How_To_Linux.git
synced 2024-12-05 01:40:32 +00:00
Compare commits
4 commits
f2a3378ab5
...
ba80482b59
Author | SHA1 | Date | |
---|---|---|---|
ba80482b59 | |||
9a29ee859e | |||
dd981a8ba8 | |||
f047a0ccc4 |
12 changed files with 424 additions and 298 deletions
|
@ -19,8 +19,9 @@
|
|||
- [CLIs of the day](day_3/clis_of_the_day.md)
|
||||
- [Tasks](day_3/tasks.md)
|
||||
- [Day 4](day_4/README.md)
|
||||
- [Advanced terminal editors](day_4/advanced_terminal_editors.md)
|
||||
- [Shell scripting](day_4/shell_scripting.md)
|
||||
- [Notes](day_4/notes.md)
|
||||
- [Python scripting](day_4/python_scripting.md)
|
||||
- [CLIs of the day](day_4/clis_of_the_day.md)
|
||||
- [Tasks](day_4/tasks.md)
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ Enter the command `mkdir empty_house`.
|
|||
Well, you don't see anything?
|
||||
Did the command do something at all?
|
||||
To check, run `ls` again.
|
||||
Now you should see your new directory `empty_house` listed too!
|
||||
Now, you should see your new directory `empty_house` listed too!
|
||||
`mkdir` stands for _make directory_.
|
||||
`empty_house` is just a name for our new directory.
|
||||
You could have used `mkdir Images` for example to create a directory called `Images`.
|
||||
|
@ -87,7 +87,7 @@ You should not be seeing anything because the directory is indeed empty, until n
|
|||
An empty house is a sad house.
|
||||
Let's give the house directory some friends to live within it.
|
||||
Enter the command `touch friend1.txt`.
|
||||
Now enter `ls` again:
|
||||
Now, enter `ls` again:
|
||||
|
||||
```console
|
||||
$ ls
|
||||
|
@ -105,7 +105,7 @@ Enter the command `cd ..` to go one directory back.
|
|||
The two dots `..` refer to the parent directory in Linux.
|
||||
|
||||
Now that you are back in `~`, enter `mv empty_house happy_house`.
|
||||
Now enter `ls` again.
|
||||
Now, enter `ls` again.
|
||||
You can see that `empty_house` does not exist anymore.
|
||||
It was renamed to `happy_house` (_since it has at least one friend now_).
|
||||
`mv` stand for _move_.
|
||||
|
@ -134,7 +134,7 @@ $ ls happy_house
|
|||
friend1.txt friend2.txt
|
||||
```
|
||||
|
||||
We did verify that `friend2.txt` was moved.
|
||||
We verified that `friend2.txt` was moved.
|
||||
Let's move `friend3.txt`, too.
|
||||
Enter `mv friend3.txt happy_house/loud_friend.txt`.
|
||||
Take a look at the content of your directory now:
|
||||
|
@ -322,7 +322,7 @@ No zombies!
|
|||
No loud housemates!
|
||||
```
|
||||
|
||||
We did use `cat` 😺 to only print the content of the file `rules.txt` without opening it with an editor.
|
||||
We used `cat` 😺 to only print the content of the file `rules.txt` without opening it with an editor.
|
||||
`cat` 🐈️ stands for _concatenate_.
|
||||
This does not sound like printing file content!?
|
||||
This is because `cat` 🐱 can be used to concatenate the content of multiple files.
|
||||
|
@ -434,7 +434,7 @@ $ wc -l -w rules.txt
|
|||
|
||||
We see that we get the number of lines and then the number of words.
|
||||
|
||||
We did learn how to access and read the manual, but how do we navigate the manual?
|
||||
We learned how to access and read the manual, but how do we navigate the manual?
|
||||
|
||||
If you open a manual with `man`, you can scroll up and down using the arrow keys.
|
||||
You can search by pressing `/`, then enter what you are search for, `lines` for example, and then press `Enter`.
|
||||
|
@ -493,10 +493,10 @@ No zombies!
|
|||
No loud housemates!
|
||||
```
|
||||
|
||||
We did copy the rules, but did you notice the dot at the end of the command `cp`?
|
||||
We copied the rules, but did you notice the dot at the end of the command `cp`?
|
||||
What does it mean?
|
||||
|
||||
We did learn that the two dots `..` refer to the parent directory (one directory back).
|
||||
We learned that the two dots `..` refer to the parent directory (one directory back).
|
||||
One dot `.` refers to the current directory.
|
||||
|
||||
Here are some **equivalent** commands that might help you understand paths in Linux:
|
||||
|
@ -566,8 +566,8 @@ For typing a long path, you can use **autocompletion**.
|
|||
Go back to the home directory using `cd`.
|
||||
Let's say that we want to read the rules of the directory `happy_house`.
|
||||
Type `cat hap` without hitting enter yet.
|
||||
Now press `Tab` and see how the path is autocompleted to `cat happy_house/` ✨
|
||||
Now type `ru` and hit `Tab` again.
|
||||
Now, press `Tab` and see how the path is autocompleted to `cat happy_house/` ✨
|
||||
Now, type `ru` and hit `Tab` again.
|
||||
Then you have `cat happy_house/rules.txt`.
|
||||
Much faster, right? 🏎️
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ For example, if you don't care about the errors that some command throughs, then
|
|||
|
||||
### More details
|
||||
|
||||
We did discuss the most important cases for redirections.
|
||||
We discussed the most important cases for redirections.
|
||||
But there are some less important details like the following:
|
||||
|
||||
- `command &>filename` is equivalent to `command >filename 2>&1`, but not to `command 2>&1 >filename` because the order matters.
|
||||
|
|
|
@ -17,7 +17,7 @@ But you should not find any updates since you did just install the crates.
|
|||
|
||||
The crate `tealdeer` provides you with the program `tldr`.
|
||||
|
||||
Run `tldr --update`. Now run the following two commands:
|
||||
Run `tldr --update`. Then run the following two commands:
|
||||
|
||||
```bash
|
||||
tldr dnf
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
# Day 4
|
||||
|
||||
Coming soon...
|
||||
Today, you will learn to write scripts for task automation.
|
||||
|
||||
We will focus on shell scripting in Bash.
|
||||
But at the end, scripting in Python is presented briefly as a more flexible scripting option in case your scripts get complicated.
|
||||
|
||||
But before we start writing our first scripts, we will learn two command line editors that offer many more features than `nano` and can make editing files much more efficient.
|
||||
|
|
132
src/day_4/advanced_terminal_editors.md
Normal file
132
src/day_4/advanced_terminal_editors.md
Normal file
|
@ -0,0 +1,132 @@
|
|||
# Advanced terminal editors
|
||||
|
||||
`nano` is fine if you just want to occasionally edit some files in the terminal.
|
||||
|
||||
But if you want to be able to edit files more efficiently, then you should consider Vim and Helix.
|
||||
|
||||
## Vim
|
||||
|
||||
Vim is a very popular _modal_ terminal editor.
|
||||
|
||||
**Modal** means that it has multiple editing modes allowing you to use your keyboard not only to type text but also to navigate and manipulate it.
|
||||
|
||||
Modal editing allows you to edit files without needing to touch the mouse.
|
||||
Being able to work without the mouse is not only good for the terminal, but it also allows you to edit code faster because you keep your hands on the keyboard and have a keybinding for everything.
|
||||
|
||||
Each mode has its keybindings.
|
||||
When you just enter Vim, then you are in the **normal mode** which has the following most important keybindings:
|
||||
|
||||
- `:q`: Quit (**very important!**)
|
||||
- `:q!`: Quit without saving (**very important!**)
|
||||
- `j`: Down
|
||||
- `k`: Up
|
||||
- `h`: Left
|
||||
- `l`: Right
|
||||
- `i`: Insert at left of cursor
|
||||
- `a`: Insert at right of cursor (append)
|
||||
- `I`: Insert at beginning of line
|
||||
- `A`: Append to end of line
|
||||
- `Esc`: Normal mode
|
||||
- `w`: Go to beginning of next word
|
||||
- `b`: Go to beginning of last word
|
||||
- `e`: Go to end of word
|
||||
- `gg`: Go to beginning of file
|
||||
- `G`: Go to end of file
|
||||
- `0`: Go to beginning of line
|
||||
- `$`: Go to end of line
|
||||
- `%`: Go to the other bracket
|
||||
- `u`: Undo
|
||||
- `Ctrl+r`: Redo
|
||||
- `:h`: Help
|
||||
- `:w`: Write buffer
|
||||
- `:wq`: Write buffer and exit
|
||||
- `/PATTERN`: Search
|
||||
- `n`: Next match
|
||||
- `N`: Previous match
|
||||
- `*`: Next match of the word under cursor
|
||||
- `o`: Add line below and enter insert mode
|
||||
- `O`: Add line above and enter insert mode
|
||||
- `v`: Start selection
|
||||
- `V`: Block selection
|
||||
- `y`: Yank (copy)
|
||||
- `p`: Paste
|
||||
- `x`: Delete one character
|
||||
- `dw`: Delete word
|
||||
- `dd`: Delete line
|
||||
- `D`: Delete util end of line
|
||||
- `cw`: Change word
|
||||
- `cc`: Change line
|
||||
- `C`: Change until end of line
|
||||
- `di(`: Delete inside bracket `(`. Can be used with other brackets and quotation marks.
|
||||
- `da(`: Same as above but delete around, not inside.
|
||||
- `ci(`: Change inside bracket `(`. Can be used with other brackets and quotation marks.
|
||||
- `ca(`: Same as above but delete around, not inside.
|
||||
- `:%s/OLD/NEW/g`: Substitute `OLD` with `NEW` in the whole file (with regex)
|
||||
- `:%s/OLD/NEW/gc`: Same as above but ask for confirmation for every substitution
|
||||
- `:N`: Go line number `N`
|
||||
- `.`: Repeat last action
|
||||
- `<` and `>`: Indentation
|
||||
- `q`: Start recording a macro (followed by macro character)
|
||||
|
||||
When you press `i` for example, then you enter the **insert mode** where you can type text.
|
||||
|
||||
There is also the **visual mode** which you can enter by pressing `v` in the normal mode.
|
||||
It allows you to select text first to then act on it.
|
||||
|
||||
You can exit the insert or visual mode by pressing the escape key `Esc`.
|
||||
|
||||
You might think that it is complicated.
|
||||
You are right, it is complicated when you start using it.
|
||||
You need to practice it for some time, but after that, the keybindings become a second nature of editing for you.
|
||||
You don't think about which keybindings to press anymore.
|
||||
You just get the muscle memory and can focus on your editing flow.
|
||||
|
||||
Should you use Vim?
|
||||
I would only recommend using it if you are editing some configuration files or small scripts in the terminal (on a server for example).
|
||||
But for programming, you should use an editor that offers more features that support you while programming.
|
||||
It should at least have [LSP](https://en.wikipedia.org/wiki/Language_Server_Protocol) (language server protocol) support.
|
||||
|
||||
The easiest option to get started with for programming on your own machine is [VS-Code](https://code.visualstudio.com/).
|
||||
For a more advanced option, the next section will present another modal terminal editor that has even more features out of the box compared with Vim.
|
||||
|
||||
So why do we bother learning Vim then?
|
||||
Althought you don't have to use Vim, you should at least learn it and be familiar with its basic keybindings.
|
||||
Not only to be able to use it when you have to, but also because Vim keybindings are widely used by other programs, especially terminal user interfaces.
|
||||
|
||||
Do you remember how we learned to navigate the manual when using `man`?
|
||||
Well, many of the keybindings that it supports are inspired by Vim!
|
||||
Examples are exiting with `q` or `:q` and searching with `/`, `n` and `N`.
|
||||
But you can also navigate the manual using `j`, `k`, `l`, `h` instead of the arrow keys!
|
||||
If you press `h` in some manual, then you see all keybindings that you can use and you will be surprised by how many are similar to Vim's.
|
||||
|
||||
> **Note**: The keybindings presented when pressing `h` are those of `less` which is a so called [terminal pager](https://en.wikipedia.org/wiki/Terminal_pager)
|
||||
>
|
||||
> It is used by other programs too, not only `man`.
|
||||
> You can also use it yourself by piping a command that produces some long output into it.
|
||||
>
|
||||
> Try running `curl -s https://dev-tools.mo8it.com` and then `curl -s https://dev-tools.mo8it.com | less` to see the difference.
|
||||
|
||||
You can even use Vim keybindings in other editors to boost your editing efficiency! 🚀
|
||||
In VS-Code for example, you get Vim keybindings by installing a plugin like [this](https://marketplace.visualstudio.com/items?itemName=vscodevim.vim).
|
||||
|
||||
> **Note**: Vim is the successor of `vi`.
|
||||
> If you are using a system that doesn't have `vim` preinstalled and you don't have superuser priviliges to install it,
|
||||
> then you will most probably at least find `vi` installed.
|
||||
|
||||
## Helix
|
||||
|
||||
Vim is the most popular modal text editor, but it is old.
|
||||
If you want to have a modal terminal text editor that can support you when coding, then try out Helix!
|
||||
|
||||
It is a modern editor written in Rust with awesome features that you can read about on [its website](https://helix-editor.com/).
|
||||
The most important one is the language server support which gives you completions, code actions, function signatures, language aware code navigation etc.
|
||||
You can watch [this video](https://www.youtube.com/watch?v=xHebvTGOdH8) for an introduction to it.
|
||||
|
||||
Most of its keybindings are similar to these of Vim.
|
||||
But it works by a selection followed by a verb like `wd` (word delete) instead of a verb followed by selection like `dw` (delete word) in Vim.
|
||||
This makes editing more intuitive since you can see what will be changed before the change happens.
|
||||
|
||||
Personally, I use Helix for all my text editing including programming and working on servers.
|
||||
Helix combined with Zellij is a powerful workspace where you can do everything efficiently in the terminal.
|
||||
It has a steep learning curve though.
|
||||
VS-Code (maybe with Vim keybindings) can often be enough 😉
|
|
@ -43,6 +43,7 @@ $ sed 's/values/strings/g' demo.txt
|
|||
here,are,some
|
||||
comma,separated,strings
|
||||
de mo,file,t x t
|
||||
|
||||
$ sed '/separated/d' demo.txt
|
||||
here,are,some
|
||||
de mo,file,t x t
|
||||
|
@ -54,11 +55,14 @@ When you specify `FILE`, you can use the option `-i` to operate _inplace_. This
|
|||
|
||||
## find
|
||||
|
||||
Find everything ending with `.sh` of type file (`f`) using globbing:
|
||||
|
||||
```bash
|
||||
# Find everything ending with `.sh` of type file `f` using globbing
|
||||
find . -type f -name '*.sh'
|
||||
```
|
||||
|
||||
Using regex:
|
||||
|
||||
# Using regex
|
||||
```bash
|
||||
find . -type f -regex '.+\.sh'
|
||||
```
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
# Notes
|
||||
|
||||
## Vim
|
||||
|
||||
- `:q`: Quit (**very important!**)
|
||||
- `:q!`: Quit without saving (**important!**)
|
||||
- `j`: Down
|
||||
- `k`: Up
|
||||
- `h`: Left
|
||||
- `l`: Right
|
||||
- `i`: Insert at left of cursor
|
||||
- `a`: Insert at right of cursor (append)
|
||||
- `I`: Insert at beginning of line
|
||||
- `A`: Append to end of line
|
||||
- `Esc`: Normal mode
|
||||
- `w`: Go to beginning of next word
|
||||
- `b`: Go to beginning of last word
|
||||
- `e`: Go to end of word
|
||||
- `gg`: Go to beginning of file
|
||||
- `G`: Go to end of file
|
||||
- `0`: Go to beginning of line
|
||||
- `$`: Go to end of line
|
||||
- `%`: Go to the other bracket
|
||||
- `u`: Undo
|
||||
- `Ctrl+r`: Redo
|
||||
- `:h`: Help
|
||||
- `:w`: Write buffer
|
||||
- `:wq`: Write buffer and exit
|
||||
- `/PATTERN`: Search
|
||||
- `n`: Next match
|
||||
- `N`: Previous match
|
||||
- `*`: Next match of the word under cursor
|
||||
- `o`: Add line below and enter insert mode
|
||||
- `O`: Add line above and enter insert mode
|
||||
- `v`: Start selection
|
||||
- `V`: Block selection
|
||||
- `y`: Yank (copy)
|
||||
- `p`: Paste
|
||||
- `x`: Delete one character
|
||||
- `dw`: Delete word
|
||||
- `dd`: Delete line
|
||||
- `D`: Delete util end of line
|
||||
- `cw`: Change word
|
||||
- `cc`: Change line
|
||||
- `C`: Change until end of line
|
||||
- `di(`: Delete inside bracket `(`. Can be used with other brackets and quotation marks.
|
||||
- `da(`: Same as above but delete around, not inside.
|
||||
- `ci(`: Change inside bracket `(`. Can be used with other brackets and quotation marks.
|
||||
- `ca(`: Same as above but delete around, not inside.
|
||||
- `:%s/OLD/NEW/g`: Substitute `OLD` with `NEW` in the whole file (with regex)
|
||||
- `:%s/OLD/NEW/gc`: Same as above but ask for confirmation for every substitution
|
||||
- `:N`: Go line number `N`
|
||||
- `.`: Repeat last action
|
||||
- `<` and `>`: Indentation
|
||||
- `q`: Start recording a macro (followed by macro character)
|
||||
|
||||
## Symlinks
|
||||
|
||||
```bash
|
||||
# Soft link
|
||||
ln -s SRC_PATH DEST_PATH
|
||||
|
||||
# Hard link
|
||||
ln SRC_PATH DEST_PATH
|
||||
```
|
||||
|
||||
## Python scripting
|
||||
|
||||
```python-repl
|
||||
>>> import subprocess
|
||||
>>> proc = subprocess.run(["ls", "student"])
|
||||
(...)
|
||||
CompletedProcess(args=['ls', '/home/student'], returncode=0)
|
||||
>>> proc.returncode
|
||||
0
|
||||
>>> proc = subprocess.run("ls /home/student", shell=True)
|
||||
(...)
|
||||
CompletedProcess(args='ls /home/student', returncode=0)
|
||||
>>> proc = subprocess.run("ls /home/student", shell=True, capture_output=True, text=True)
|
||||
CompletedProcess(args='ls /home/student', returncode=0, stdout='(...)', stderr='')
|
||||
>>> proc.stdout
|
||||
(...)
|
||||
>>> proc.stderr
|
||||
>>> proc = subprocess.run("ls /home/nonexistent", shell=True, capture_output=True, text=True)
|
||||
CompletedProcess(args='ls /home/nonexistent', returncode=2, stdout='', stderr="ls: cannot access '/home/nonexistent': No such file or directory\n")
|
||||
>>> proc = subprocess.run("ls /home/nonexistent", shell=True, capture_output=True, text=True, check=True)
|
||||
---------------------------------------------------------------------------
|
||||
CalledProcessError Traceback (most recent call last)
|
||||
Input In [8], in <cell line: 1>()
|
||||
----> 1 subprocess.run("ls /home/nonexistent", shell=True, capture_output=True, text=True, check=True)
|
||||
|
||||
File /usr/lib64/python3.10/subprocess.py:524, in run(input, capture_output, timeout, check, *popenargs, **kwargs)
|
||||
522 retcode = process.poll()
|
||||
523 if check and retcode:
|
||||
--> 524 raise CalledProcessError(retcode, process.args,
|
||||
525 output=stdout, stderr=stderr)
|
||||
526 return CompletedProcess(process.args, retcode, stdout, stderr)
|
||||
|
||||
CalledProcessError: Command 'ls /home/nonexistent' returned non-zero exit status 2.
|
||||
```
|
||||
|
||||
Most used modules when writing system scripts with Python: `pathlib`, `os`, `shutil`.
|
||||
|
||||
```python-repl
|
||||
>>> from pathlib import Path
|
||||
>>> p = Path.home() / "day_5"
|
||||
PosixPath('/home/student/day_5')
|
||||
>>> p.is_dir()
|
||||
(...)
|
||||
>>> p.is_file()
|
||||
(...)
|
||||
>>> p.exists()
|
||||
(...)
|
||||
>>> p.chmod(0o700)
|
||||
(...)
|
||||
>>> rel = Path(".")
|
||||
PosixPath('.')
|
||||
>>> rel.resolve()
|
||||
PosixPath('/home/student/(...)')
|
||||
```
|
63
src/day_4/python_scripting.md
Normal file
63
src/day_4/python_scripting.md
Normal file
|
@ -0,0 +1,63 @@
|
|||
# Python scripting
|
||||
|
||||
Bash scripts are fine if your script is not complicated.
|
||||
But Bash is ugly and if you try for example to use arrays/lists in Bash, you probably should just use Python for what are trying to accomplish with your Bash script.
|
||||
|
||||
You can use what you have learned about running programs and feed Python with commands that it can run:
|
||||
|
||||
```python-repl
|
||||
>>> import subprocess
|
||||
|
||||
>>> proc = subprocess.run(["ls", "student"])
|
||||
(…)
|
||||
CompletedProcess(args=['ls', '/home/student'], returncode=0)
|
||||
|
||||
>>> proc.returncode
|
||||
0
|
||||
|
||||
>>> proc = subprocess.run("ls /home/student", shell=True)
|
||||
(…)
|
||||
CompletedProcess(args='ls /home/student', returncode=0)
|
||||
|
||||
>>> proc = subprocess.run("ls /home/student", shell=True, capture_output=True, text=True)
|
||||
CompletedProcess(args='ls /home/student', returncode=0, stdout='(…)', stderr='')
|
||||
|
||||
>>> proc.stdout
|
||||
(…)
|
||||
|
||||
>>> proc.stderr
|
||||
|
||||
>>> proc = subprocess.run("ls /home/nonexistent", shell=True, capture_output=True, text=True)
|
||||
CompletedProcess(args='ls /home/nonexistent', returncode=2, stdout='', stderr="ls: cannot access '/home/nonexistent': No such file or directory\n")
|
||||
|
||||
>>> proc = subprocess.run("ls /home/nonexistent", shell=True, capture_output=True, text=True, check=True)
|
||||
---------------------------------------------------------------------------
|
||||
CalledProcessError Traceback (most recent call last)
|
||||
(…)
|
||||
```
|
||||
|
||||
The most used modules when writing system scripts with Python are `pathlib`, `os`, `shutil`.
|
||||
|
||||
```python-repl
|
||||
>>> from pathlib import Path
|
||||
>>> p = Path.home() / "day_5"
|
||||
PosixPath('/home/student/day_5')
|
||||
|
||||
>>> p.is_dir()
|
||||
(…)
|
||||
|
||||
>>> p.is_file()
|
||||
(…)
|
||||
|
||||
>>> p.exists()
|
||||
(…)
|
||||
|
||||
>>> p.chmod(0o700)
|
||||
(…)
|
||||
|
||||
>>> rel = Path(".")
|
||||
PosixPath('.')
|
||||
|
||||
>>> rel.resolve()
|
||||
PosixPath('/home/student/(…)')
|
||||
```
|
|
@ -1,10 +1,18 @@
|
|||
# Shell scripting
|
||||
|
||||
Task automation requires multiple instructions that have to run on demand. To combine multiple instructions, we need to write a shell script.
|
||||
Task automation requires multiple instructions that have to run on demand.
|
||||
To combine multiple commands together for automation, we need to write a shell script.
|
||||
|
||||
Since `bash` is the default shell on most Linux distributions, we learn bash scripting.
|
||||
Since Bash is the default shell on most Linux distributions, we will learn Bash scripting.
|
||||
|
||||
## First bash script
|
||||
Although I recommend using the Fish shell when using the terminal and although Fish supports scripting too, I would not recommend using it for scripting since you would not be able to share and run these scripts anywhere.
|
||||
You need to have Fish installed which is not always the case.
|
||||
|
||||
I use Fish for my personal scripts.
|
||||
But if I write a script that will be shared with others, then I write it in Bash.
|
||||
Learn to write Bash scripts first before considering using Fish scripts, even for your personal scripts.
|
||||
|
||||
## First Bash script
|
||||
|
||||
Let's write our first Bash script:
|
||||
|
||||
|
@ -33,32 +41,36 @@ fi
|
|||
|
||||
Copy this code into a file called `which-os.sh`.
|
||||
|
||||
Now run `chmod u+x which-os.sh`. Then run `./which-os.sh`. Don't worry, everything will be explained afterwards.
|
||||
Now, run `chmod u+x which-os.sh`.
|
||||
Then run `./which-os.sh`.
|
||||
Don't worry, everything will be explained afterwards.
|
||||
|
||||
After running the script, you will see a prompt asking you to enter a number corresponding to an operating system. If you choose Linux, you get the output "Good choice". This output is in the standard output.
|
||||
After running the script, you will see a prompt asking you to enter a number corresponding to an operating system.
|
||||
If you choose Linux, you get the output "Good choice".
|
||||
This output is in the standard output.
|
||||
|
||||
If you don't choose Linux, you get the output "Nah, that can't be right! (...)". This output is redirected to the standard error.
|
||||
If you don't choose Linux, you get the output "Nah, that can't be right! (...)".
|
||||
This output is redirected to the standard error.
|
||||
|
||||
We did learn that we can redirect to a file using `>`. The syntax `1>&2` redirects the standard output to the standard error. On the other hand. `2>&1` redirects the standard error to the standard output.
|
||||
|
||||
If you want to redirect both the standard output and error to a file, you can use this syntax: `COMMAND >FILE 2>&1`.
|
||||
|
||||
The redirection **order** is important in this case! `COMMAND 2>&1 >FILE` will redirect the standard output **only** to the file `FILE`!
|
||||
|
||||
`COMMAND >FILE 2>&1` has a useful shortcut: `COMMAND &>FILE`. You can also use `&>>` to append.
|
||||
|
||||
All other aspects of the script above will be explained in the next sections.
|
||||
The building blocks of the script above will be explained in the next sections.
|
||||
|
||||
## Shebang
|
||||
|
||||
The first line of our first script starts with `#!` which is called the _shebang_. The shebang is followed by the program that runs the script. Since the script is a bash script, we use the program `bash` to run it. But writing `bash` after the shebang is not enough. We have to specify the path to the program. We can find out the path of the program by using the command `which`:
|
||||
The first line of our first script starts with `#!` which is called the _shebang_.
|
||||
The shebang is followed by the program that runs the script.
|
||||
Since the script is a Bash script, we use the program `bash` to run it.
|
||||
|
||||
But writing `bash` after the shebang is not enough.
|
||||
We have to specify the full path to the program.
|
||||
We can find out the path of a program by using the command `which`:
|
||||
|
||||
```console
|
||||
$ which bash
|
||||
/usr/bin/bash
|
||||
```
|
||||
|
||||
You can also write a Python script and add a shebang at its beginning. We can find out the path to the Python program:
|
||||
You can also write a Python script and add a shebang at its beginning.
|
||||
We can find out the path to the Python interpreter by running the following:
|
||||
|
||||
```console
|
||||
$ which python3
|
||||
|
@ -77,31 +89,37 @@ Let's save this tiny Python script as `hello_world.py`, make it executable with
|
|||
|
||||
```console
|
||||
$ chmod u+x hello_world.py
|
||||
|
||||
$ ./hello_world.py
|
||||
Hello world!
|
||||
```
|
||||
|
||||
We could have written the Python script without the shebang, but then we would have to run with `python3 hello_world.py`. Adding the shebang lets you see a script as a program and ignore what language it is written in when running it.
|
||||
We could have written the Python script without the shebang, but then we would have to run with `python3 hello_world.py`.
|
||||
Adding the shebang lets you see a script as a program and ignore what language it is written in when running it.
|
||||
|
||||
You can use the shebang with any program that runs a script (interpreter).
|
||||
You can use the shebang with any program that can run a script.
|
||||
|
||||
## Variables
|
||||
|
||||
In our first bash script, we have the line `RIGHT_ANSWER=1`. This line defines a variable with the name `RIGHT_ANSWER` and the value `1`.
|
||||
In our first Bash script, we have the line `RIGHT_ANSWER=1`.
|
||||
This line defines a variable with the name `RIGHT_ANSWER` and the value `1`.
|
||||
|
||||
To define a variable in bash, you have to write the name of the variable _directly_ followed by an equal sign `=`. The equal sign has to be _directly_ followed by the value of the variable.
|
||||
To define a variable in Bash, you have to write the name of the variable **directly** followed by an equal sign `=`.
|
||||
The equal sign has to be **directly** followed by the value of the variable.
|
||||
|
||||
_directly followed_ means that spaces between the variable name, the equal sign `=` and the value are not allowed!
|
||||
_directly followed by_ means that spaces between the variable name, the equal sign `=` and the value are not allowed!
|
||||
|
||||
But what if you want to set a variable equal to a string that contains spaces?
|
||||
|
||||
In this case, you have to use quotation marks `"`. For example:
|
||||
In that case, you have to use quotation marks `"`.
|
||||
For example:
|
||||
|
||||
```bash
|
||||
HELLO="Hello world!"
|
||||
```
|
||||
|
||||
To use a defined variable, we use a dollar sign `$` before the variable name. For example:
|
||||
To read the value of a defined variable, we use a dollar sign `$` before the variable name.
|
||||
For example:
|
||||
|
||||
```bash
|
||||
echo $HELLO
|
||||
|
@ -118,9 +136,10 @@ echo $MESSAGE
|
|||
|
||||
The two lines above would lead to the output `Tux says: Hello world!`.
|
||||
|
||||
## Capturing command's output
|
||||
## Capturing command output
|
||||
|
||||
You can capture the standard output of a command using the the syntax `$(COMMAND)`. Example:
|
||||
You can capture the standard output of a command using the the syntax `$(COMMAND)`.
|
||||
Example:
|
||||
|
||||
```bash
|
||||
BASH_VERSION=$(bash --version)
|
||||
|
@ -132,8 +151,8 @@ Let's run the command in the terminal first to see its output:
|
|||
|
||||
```console
|
||||
$ bash --version
|
||||
GNU bash, version 5.1.16(1)-release (x86_64-redhat-linux-gnu)
|
||||
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
GNU bash, version 5.2.15(1)-release (x86_64-redhat-linux-gnu)
|
||||
Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
||||
|
||||
This is free software; you are free to change and redistribute it.
|
||||
|
@ -144,10 +163,11 @@ Now, let's output the variable that we did define above:
|
|||
|
||||
```console
|
||||
$ echo $BASH_VERSION
|
||||
GNU bash, version 5.1.16(1)-release (x86_64-redhat-linux-gnu) Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
|
||||
GNU bash, version 5.2.15(1)-release (x86_64-redhat-linux-gnu) Copyright (C) 2022 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
|
||||
```
|
||||
|
||||
You can see that the lines are squashed into one line! If you want to output the lines without them being squashed, you have to use quotation marks `"`:
|
||||
You can see that the lines are squashed into one line!
|
||||
If you want to output the lines without them being squashed, you have to use quotation marks `"`:
|
||||
|
||||
```console
|
||||
$ echo "$BASH_VERSION"
|
||||
|
@ -159,9 +179,9 @@ This is free software; you are free to change and redistribute it.
|
|||
There is NO WARRANTY, to the extent permitted by law.
|
||||
```
|
||||
|
||||
This is the output that we did expect 😃
|
||||
This is the output that we expect 😃
|
||||
|
||||
## Temporary variables
|
||||
## Environment variables
|
||||
|
||||
Let's write the following tiny script `hello.sh`:
|
||||
|
||||
|
@ -171,15 +191,20 @@ Let's write the following tiny script `hello.sh`:
|
|||
echo "Hello $USER!"
|
||||
```
|
||||
|
||||
Now we run the script. The output on my machine is:
|
||||
Now, we run the script.
|
||||
The output on my machine is:
|
||||
|
||||
```console
|
||||
$ chmod u+x hello.sh
|
||||
|
||||
$ ./hello.sh
|
||||
Hello mo!
|
||||
Hello mo8it!
|
||||
```
|
||||
|
||||
We see `Hello mo!` as output. This is because my user name on my machine is `mo`. `USER` is a so called environment variable that is defined for all programs. If you run the script on your machine, you will get your user name instead of `mo`. There are more environment variables like `PATH` which we will learn about later.
|
||||
We see `Hello mo8it!` as output.
|
||||
This is because my user name on my machine is `mo8it`.
|
||||
`USER` is a so called **environment variable** that is defined for all programs.
|
||||
If you run the script on your machine, you will get your username instead of `mo8it`.
|
||||
|
||||
Now, let's run the following:
|
||||
|
||||
|
@ -188,27 +213,56 @@ $ USER=Tux ./hello.sh
|
|||
Hello Tux!
|
||||
```
|
||||
|
||||
We did define a temporary variable `USER` with the value `Tux`. This temporary variable overwrites the environment variable `USER` in our script. Therefore we get the output `Hello Tux!` and not our user name.
|
||||
We defined an environment variable `USER` with the value `Tux` just before running the script.
|
||||
This variable overwrites the global value of the variable `USER` in our script.
|
||||
Therefore we get the output `Hello Tux!` and not our user name.
|
||||
|
||||
You can use temporary variables not only to overwrite environment variables. These are basically variables that can be used by the program that you specify after their definition.
|
||||
You can use environment variables not only to overwrite existing ones variables.
|
||||
These are basically variables that can be used by the program that you specify after their definition.
|
||||
|
||||
## Comments
|
||||
|
||||
In our first bash script, you can find three lines starting with a hashtag `#`. Two lines are comments, the shebang `#!` is an exception as a special comment at the beginning of a file that is not ignored while running the script. All other lines that start with `#` are comments that are ignored by the computer. Comments are only for humans to explain things.
|
||||
In our first Bash script, you can find three lines starting with a hashtag `#`.
|
||||
Two lines are comments, the shebang `#!` is an exception as a special comment at the beginning of a file that is not ignored while running the script.
|
||||
All other lines that start with `#` are comments that are ignored by the computer.
|
||||
Comments are only for humans to explain things.
|
||||
|
||||
Especially in long scripts, you should write comments to explain what the script and its "non trivial sections" do.
|
||||
Especially in long scripts, you should write comments to explain what the script itself and its "non trivial sections" do.
|
||||
|
||||
## User input
|
||||
|
||||
In a script, you can ask for user input. To do so, you can use the command `read`.
|
||||
In a script, you can ask for user input.
|
||||
To do so, you can use the command `read`.
|
||||
|
||||
In our first bash script, we use `read` to take the answer of the user. The input is then saved in the variable `ANSWER`. You can choose a different name for this variable. After the line with `read`, you can use the variable storing the input as a normal variable.
|
||||
In our first Bash script, we use `read` to ask the user for his answer.
|
||||
The input is then saved in the variable `ANSWER`.
|
||||
You can choose a different name for this variable.
|
||||
After the line with `read`, you can use the variable storing the input as a normal variable.
|
||||
|
||||
## Arguments
|
||||
|
||||
To read the `n`-th argument that is provided to a script, we can use `$n`.
|
||||
|
||||
Take a look at the following example script called `arg.sh`:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/bash
|
||||
|
||||
echo "The first argument is: $1"
|
||||
```
|
||||
|
||||
When you run this script with an argument, you get the following output:
|
||||
|
||||
```console
|
||||
$ ./arg.sh "Hello"
|
||||
The first argument is: Hello
|
||||
```
|
||||
|
||||
## Conditions
|
||||
|
||||
### `if` block
|
||||
|
||||
Our first bash script checks if the user input which is stored in the variable `ANSWER` equals the variable `RIGHT_ANSWER` which stores the value `1`.
|
||||
Our first Bash script checks if the user input which is stored in the variable `ANSWER` equals the variable `RIGHT_ANSWER` which stores the value `1`.
|
||||
|
||||
To check for a condition in Bash, we use the following syntax:
|
||||
|
||||
|
@ -221,11 +275,14 @@ fi
|
|||
|
||||
Here, `(...)` stands for the commands that we want to run if the condition is true.
|
||||
|
||||
In our first bash script, we check for equality of two variables with a double equal sign `==`.
|
||||
In our first Bash script, we check for equality of two variables with a double equal sign `==`.
|
||||
|
||||
`fi` is not a typo! It is just `if` reversed to indicate the end of the `if` block. Although the syntax is not the best, you have to sadly accept it. Bash does not have the best syntax...
|
||||
`fi` is not a typo! It is just `if` reversed to indicate the end of the `if` block.
|
||||
Although the syntax is not the best, you have to sadly accept it.
|
||||
Bash does not have the best syntax...
|
||||
|
||||
Speaking about syntax: You have to take spaces seriously with conditions.
|
||||
Speaking about syntax:
|
||||
You have to take spaces seriously with conditions.
|
||||
|
||||
For example, if we define the variable `VAR=1`, the following snippets **do not work** (or have an unexpected behavior):
|
||||
|
||||
|
@ -236,7 +293,6 @@ For example, if we define the variable `VAR=1`, the following snippets **do not
|
|||
echo "VAR has the value 1"
|
||||
fi
|
||||
```
|
||||
|
||||
1. No space before `]`
|
||||
```bash
|
||||
if [ $VAR == 1]
|
||||
|
@ -266,7 +322,7 @@ For example, if we define the variable `VAR=1`, the following snippets **do not
|
|||
fi
|
||||
```
|
||||
|
||||
But the following snippet **work**:
|
||||
But the following snippet **works**:
|
||||
|
||||
- Space after `[`, before `]`, before `==` and after `==`
|
||||
```bash
|
||||
|
@ -278,7 +334,8 @@ But the following snippet **work**:
|
|||
|
||||
### `else` block
|
||||
|
||||
The `else` block runs commands inside it only if the condition is not true. The syntax is:
|
||||
The `else` block runs commands inside it only if the `if` condition is false.
|
||||
The syntax is:
|
||||
|
||||
```bash
|
||||
if [ CONDITION ]
|
||||
|
@ -302,24 +359,18 @@ else
|
|||
fi
|
||||
```
|
||||
|
||||
<!-- TODO: else -->
|
||||
|
||||
<!-- TODO: else if -->
|
||||
|
||||
<!-- TODO: test -->
|
||||
|
||||
<!-- TODO: if [ ! -f ] -->
|
||||
|
||||
<!-- TODO: case -->
|
||||
|
||||
<!-- TODO: for -->
|
||||
|
||||
<!-- TODO: while -->
|
||||
|
||||
<!-- TODO: command | while read -->
|
||||
|
||||
<!-- TODO: math (( )) -->
|
||||
|
||||
<!-- TODO: Long command on multiple lines \ -->
|
||||
|
||||
<!-- Why ./SCRIPT_NAME -->
|
||||
|
@ -333,5 +384,3 @@ fi
|
|||
<!-- TODO: chmod codes -->
|
||||
|
||||
<!-- TODO: https://chmodcommand.com -->
|
||||
|
||||
Rest coming soon...
|
||||
|
|
|
@ -1,150 +1,142 @@
|
|||
# Tasks
|
||||
|
||||
## Task: Vim macros
|
||||
Don't forget to add a shebang to your scripts and make them executable!
|
||||
|
||||
In this task, we will learn about the power of macros in Vim.
|
||||
## Task: Essential tools
|
||||
|
||||
1. Visit [this URL](https://www.randomlists.com/random-names?qty=500), select the generated 500 names with the mouse and copy them.
|
||||
1. Create a new text file and open it with `vim`.
|
||||
1. Paste the names into the file. You should see 500 lines with a name in each line.
|
||||
1. Record a macro that changes a line in the form `FIRST_NAME LAST_NAME` to `("FIRST_NAME", "LAST_NAME"),`.
|
||||
1. Run the macro on all lines.
|
||||
1. Now go to the beginning of the file (`gg`) and add this line as a first line: `names = [`
|
||||
1. Go to the end of the file (`G`) and add this line as last line: `]`
|
||||
Write a Bash script that installs the following _essential_ Linux packages for you:
|
||||
|
||||
Congratulations, you did just convert the names into a form that could be directly used by a Python program! It is a list of tuples now.
|
||||
- `cmatrix`
|
||||
- `cowsay`
|
||||
- `lolcat`
|
||||
- `fortune`
|
||||
|
||||
After the installation is done, the script should let `cowsay` inform the user that the insallation was successful.
|
||||
|
||||
Test your script!
|
||||
|
||||
> **Fun**: Run the command `cbonsai -i -l -t 0.01 -w 1` 🌳
|
||||
|
||||
## Task: Current directory
|
||||
|
||||
Write a Bash script that calculates the total number of files and directories (together) in the current directory.
|
||||
For example, if the current directory has two directories and one file, then the number would be `3`.
|
||||
Store the result into a variable.
|
||||
|
||||
The output should be the full path to the current working directory with a message telling about the calculated number.
|
||||
Example:
|
||||
|
||||
```console
|
||||
$ whereami.sh
|
||||
You are in the directory /home/student/scripts
|
||||
There are 3 files and directories in this directory.
|
||||
```
|
||||
|
||||
### Hints
|
||||
|
||||
- `ls -l` shows every file or directory in the current directory on a separate line.
|
||||
|
||||
## Task: Backup then update
|
||||
|
||||
Write a Bash script that does the following:
|
||||
|
||||
1. Create the directory `~/installed_packages` if it does not exist. If it exists, it should not through any errors.
|
||||
1. Stores the output of the command `dnf list --installed` into the file `~/installed_packages/dnf.txt`.
|
||||
1. Stores the output of the command `cargo install --list` into the file `~/installed_packages/cargo.txt`.
|
||||
1. Installs system upgrades using `dnf`.
|
||||
1. Installs Cargo updates.
|
||||
1. Check if `cowsay` is installed. Only if not, install it first. After that, `cowsay` should inform you that installed packages where logged into the directory `~/installed_packages` and updates were successfully installed.
|
||||
|
||||
If any of the steps above fails, the script should stop and not continue.
|
||||
This can be achieved by adding the following line to the beginning of the script (after the shebang): `set -e`.
|
||||
|
||||
## Task: Scripted "Gimme that PDF" 😈
|
||||
|
||||
On day 2, you downloaded a PDF given some web page link.
|
||||
We want to write a script now that is generic over the web page link.
|
||||
|
||||
It should ask the user for a web page link and then download the PDF if a PDF link was found on that web page.
|
||||
|
||||
The script should exit with the status code 1 while printing an error message to stderr in case no PDF link was found on the web page ❌
|
||||
|
||||
Otherwise, it should print a message to stdout that the download was sucessful ✔️
|
||||
|
||||
## Task: Job scheduler
|
||||
|
||||
> Warning ⚠️ : This task is not an easy task. Don't give up quickly and ask for help if you don't get further!
|
||||
> **Warning** ⚠️ : This task is not an easy one.
|
||||
> Don't give up quickly and ask for help if you don't get further!
|
||||
|
||||
In this task, we want to write our own job scheduler.
|
||||
|
||||
Understanding how job schedulers work is important when you are working on a computer cluster.
|
||||
|
||||
Computer clusters are shared by many users. Therefore, running jobs on a cluster has to be scheduled to make sure that the resources are shared probably.
|
||||
Computer clusters are shared by many users.
|
||||
Therefore, running jobs on a cluster has to be scheduled to make sure that the resources are shared probably.
|
||||
|
||||
In this task, we will keep it simple. No aspects of multiple users or any optimizations.
|
||||
In this task, we will keep it simple.
|
||||
No aspects of multiple users or any optimizations.
|
||||
|
||||
We want to be able to submit a job as a single script (without any dependencies). The submitted scripts should run one after the another to save CPU usage for example.
|
||||
We want to be able to submit a job as a single script (without any dependencies).
|
||||
The submitted scripts should run one after the another.
|
||||
|
||||
We will use the program `inotifywait`. This program can monitor a directory and notify on changes within this directory.
|
||||
We will use the program `inotifywait`.
|
||||
This program can monitor a directory and notify on changes within this directory.
|
||||
|
||||
1. Find out which package installs `inotifywait` and install it.
|
||||
1. Start Zellij if you are not already using it.
|
||||
1. Find out which package porvides the program `inotifywait` and install it.
|
||||
1. Read the manual of `inotifywait` for a better understanding of what it does.
|
||||
1. Find out how to tell `inotifywait` to keep monitoring a directory and not exit after the first event.
|
||||
1. Find out what events mean in the context of `inotifywait`.
|
||||
1. Find out how to tell `inotifywait` to keep monitoring a directory and not exit after the first event.
|
||||
1. Create a new directory called `jobs` to be monitored.
|
||||
1. Create a new directory called `logs` that will be used later.
|
||||
1. Run `inotifywait` while telling it to monitor the directory `jobs`. Leave the command running in a terminal and open a second terminal (tab) to continue the work in.
|
||||
1. Run `inotifywait` while telling it to monitor the directory `jobs`. Leave the command running in one Zellij pane and open a second pane to continue the work in.
|
||||
1. Create a file **outside** of the directory `jobs` and then copy it to the directory `jobs`.
|
||||
1. Go back to the first terminal and see the output of `inotifywait` was.
|
||||
1. Based on the output, choose an event that you want to listen to with `inotifywait` that tells you when a file is _completely_ added to the directory `jobs`. Use the manual to read more about specific events.
|
||||
1. Look at the output of `inotifywait` in the first pane after copying the file in to the `jobs` directory.
|
||||
1. Based on that output, choose an event that you want to listen to with `inotifywait` that tells you when a file is **completely written** to the directory `jobs`. Use the manual to read more about specific events.
|
||||
1. Find an option that lets you tell `inotifywait` to only notify when the chosen event occurs.
|
||||
1. Find an option that lets you format the output of the notification of `inotifywait`. Since we only listen on one event and monitor only one directory, an output that shows only the name of the new file should be enough.
|
||||
1. Enter the command that you have until now in a script. Now extend it by using a `while` loop that continuously listens on the notifications of `inotifywait`. Use the following snippet while replacing the sections with `(...)`:
|
||||
1. Find an option that lets you format the output of the notification of `inotifywait`. Since we only listen on one event and monitor only one directory, an output that shows **only the name of the new file** should be enough.
|
||||
1. Enter the `inotifywait` command that you have until now in a script. Now, extend it by using a `while` loop that continuously listens on the notifications of `inotifywait`. Use the following snippet after replacing `…`:
|
||||
```bash
|
||||
inotifywait (...) | while read FILENAME
|
||||
inotifywait … | while read NEW_SCRIPT_NAME
|
||||
do
|
||||
(...)
|
||||
…
|
||||
done
|
||||
```
|
||||
1. After a notification, the body of the `while` loop should first print the name of the script that was added. From now on, we only want to add scripts to the `jobs` directory.
|
||||
1. After printing the script name, run the script!
|
||||
1. After a notification, the body of the `while` loop should first print the name of the script that was added (`NEW_SCRIPT_NAME`). Then, the new script should be run.
|
||||
1. Save the standard output and standard error of the script into two separate files in the `logs` directory. If the name of the script is `job.sh` for example, then the output should be in the files `logs/job.sh.out` and `logs/job.sh.err`.
|
||||
|
||||
### Hints
|
||||
|
||||
- Take a look at the examples from the sections of this day.
|
||||
- Take care of permissions.
|
||||
|
||||
If you have extra time, read about the command `screen` in the internet. `screen` allows you to run commands in the background. This way, you don't need two terminals.
|
||||
- Take care of file permissions.
|
||||
|
||||
## Task: Job submitter
|
||||
|
||||
In this task we will write a small script that lets us submit a job script to the scheduler from the last task.
|
||||
In this task, we will write a small script called submitter that lets us submit a job script to the scheduler from the last task.
|
||||
|
||||
The script should take the path to the job script as a single required argument.
|
||||
The submitter should take the path to the job script as a single required argument.
|
||||
|
||||
The script should then copy the job script to the directory `jobs` while adding the time and date to the beginning of the name of the job script in the `jobs` directory.
|
||||
The submitter should then copy the job script to the directory `jobs` while adding the current time and date as a prefix to the new job script name.
|
||||
|
||||
Read the manual of the command `date` to know how to get the time and date in the following format: `2022-08-22T20:00:00+00:00`.
|
||||
Read the manual of the command `date` to know how to get the current time and date in the following format: `2022-08-22T20:00:00+00:00`.
|
||||
|
||||
If the name of the job script is `job.sh` for example, the job script should be named `2022-08-22T20:00:00+00:00_job.sh` in the `jobs` directory.
|
||||
|
||||
Use variables to write the script to make it more understandable.
|
||||
Use variables while writing the script to make it more understandable.
|
||||
|
||||
#### Help
|
||||
### Hints
|
||||
|
||||
To save the output of a command into a variable, use you have to use the following syntax:
|
||||
|
||||
```bash
|
||||
DATE=$(date ...)
|
||||
```
|
||||
|
||||
Replace `...` with your code.
|
||||
|
||||
To read the `n`-th argument that is provided to a script you write, you have to use `$n`.
|
||||
|
||||
Example script called `arg.sh`:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/bash
|
||||
|
||||
echo "The first argument is: $1"
|
||||
```
|
||||
|
||||
When you run this script with an argument:
|
||||
|
||||
```console
|
||||
$ ./arg.sh "Hello"
|
||||
The first argument is: Hello
|
||||
```
|
||||
- To save the output of a command into a variable, you have to use the following syntax after replacing `…`:
|
||||
```bash
|
||||
DATETIME=$(date …)
|
||||
```
|
||||
|
||||
## Task: Submit a job
|
||||
|
||||
Write a small scripts of your choice that require a long time to run and submit them using the script from the last task. Make sure that the scheduler is running in the background.
|
||||
Write a small job script that requires at least 10 seconds to run (can be simulated with the command `sleep 10`).
|
||||
Submit that job script by using the submitter from the last task.
|
||||
|
||||
You can use the command `sleep` to simulate a job that needs long time to run.
|
||||
Make sure that the scheduler is running in one Zellij pane before submitting.
|
||||
|
||||
Submit your job script multiple times and take a look at the terminal that is running the scheduler to make sure that the job scripts are running one after the other.
|
||||
Submit your job script multiple times and take a look at the pane where scheduler is running to make sure that the job scripts are running one after the other.
|
||||
|
||||
Verify the redirection of the standard output and standard error in the directory `logs`.
|
||||
|
||||
## Task: Parsing a CSV file
|
||||
|
||||
1. Use `curl` to take a look at the file with the following link: [https://gitlab.rlp.net/mobitar/julia\_course/-/raw/main/Day\_3/resources/fitting\_task\_data.csv](https://gitlab.rlp.net/mobitar/julia_course/-/raw/main/Day_3/resources/fitting_task_data.csv). The file contains measurement of a (fake) free fall experiment.
|
||||
1. Now that you know what the file contains, pipe the output to tools that let you remove the first 6 and last 2 lines. Afterwards, extract the first (measured height) and third column (measured time).
|
||||
1. Write a small Python that processes the output of the command from the last step. Since this book is not about programming in Python or plotting, the simple code to process the output of the variable `h_t` is given below:
|
||||
|
||||
```
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
(...)
|
||||
|
||||
h_values = []
|
||||
t_values = []
|
||||
|
||||
for line in h_t.strip().split("\n"):
|
||||
h, t = line.strip().split(",")
|
||||
h_values.append(h)
|
||||
t_values.append(t)
|
||||
|
||||
plt.plot(h_values, t_values)
|
||||
plt.xlabel("h")
|
||||
plt.ylabel("t")
|
||||
plt.savefig("h_t.pdf")
|
||||
```
|
||||
|
||||
Use the command that you did write in the last step to extract the two columns and save the output in a variable called `h_t` in the `(...)` block.
|
||||
1. Save the Python script into a file in an empty directory called `bash_python_harmony`.
|
||||
1. Use `poetry` to initialize an environment in the directory `bash_python_harmony`.
|
||||
1. Use `poetry` to add the package `matplotlib` to the environment.
|
||||
1. Use `poetry shell` to enter the environment.
|
||||
1. Run the script and check the generated PDF file `h_t.pdf`.
|
||||
|
||||
## Task: Python rewrite
|
||||
|
||||
Choose one of the scripts that you have written during the course and rewrite it in Python!
|
||||
|
|
|
@ -28,7 +28,7 @@ After that I add you public key, connect to the server using the host name that
|
|||
|
||||
Replace `USERNAME` with your name.
|
||||
|
||||
1. Now set a password for the new user:
|
||||
1. Now, set a password for the new user:
|
||||
|
||||
```bash
|
||||
sudo passwd USERNAME
|
||||
|
@ -94,16 +94,16 @@ In this task, we want to compile the program `tmate`.
|
|||
1. Go to the [website of `tmate`](https://tmate.io/) and find out how to compile from source (there are instructions for compiling on Ubuntu).
|
||||
1. Follow the compilation instructions in the container.
|
||||
1. After compilation, you will find the binary `tmate` in the directory of the git repository.
|
||||
1. Don't exit the container yet, otherwise you will lose what you have done in it. Now open a new terminal (tab) and copy the binary `tmate` from the container to the directory `bin` in your home directory. Use the command `podman cp CONTAINERNAME:SRC_PATH DESTINATION_PATH`.
|
||||
1. Don't exit the container yet, otherwise you will lose what you have done in it. Now, open a new terminal (tab) and copy the binary `tmate` from the container to the directory `bin` in your home directory. Use the command `podman cp CONTAINERNAME:SRC_PATH DESTINATION_PATH`.
|
||||
1. Verify that the binary `tmate` was copied to `DESTINATION_PATH` and then exit the container in the first terminal (tab).
|
||||
|
||||
Now write a script called `compile_tmate.sh` that automates what you have done in the container to compile `tmate`. Just copy all the commands that you used in the container to a script.
|
||||
Now, write a script called `compile_tmate.sh` that automates what you have done in the container to compile `tmate`. Just copy all the commands that you used in the container to a script.
|
||||
|
||||
Add to the end of the script `mv PATH_TO_TMATE_BINARY_IN_CONTAINER /volumes/bin` to copy the binary to the directory `/volumes/bin` after compilation.
|
||||
|
||||
Create a directory called `scripts` and put the script in it.
|
||||
|
||||
Now write a second script in the parent directory of the directory `scripts`. The second script should automate creating the container that runs the first script.
|
||||
Now, write a second script in the parent directory of the directory `scripts`. The second script should automate creating the container that runs the first script.
|
||||
|
||||
Do the following in the second script:
|
||||
|
||||
|
@ -129,7 +129,7 @@ Do the following in the second script:
|
|||
|
||||
After running the second script, you should see the container compiling and then exiting. At the end, you should find the binary `tmate` in the `bin` directory.
|
||||
|
||||
Now that you have the program `tmate`, find out what it does! Try it with a second person.
|
||||
Now, that you have the program `tmate`, find out what it does! Try it with a second person.
|
||||
|
||||
### Hints
|
||||
|
||||
|
|
Loading…
Reference in a new issue