mirror of
https://codeberg.org/Mo8it/How_To_Linux.git
synced 2024-11-21 18:08:03 +00:00
Done day 5
This commit is contained in:
parent
a1a483ffd8
commit
84a05eac98
4 changed files with 361 additions and 14 deletions
|
@ -17,3 +17,5 @@
|
|||
- [Notes](day_4/notes.md)
|
||||
- [Tasks](day_4/tasks.md)
|
||||
- [Day 5](day_5/README.md)
|
||||
- [Notes](day_5/notes.md)
|
||||
- [Tasks](day_5/tasks.md)
|
||||
|
|
|
@ -193,17 +193,3 @@ In this task, we are going to play a game! 🎮️
|
|||
The game is an educational game that lets you learn the very basics of the navigation in Vim/Neovim.
|
||||
|
||||
Play the game on this website: [https://vim-adventures.com](https://vim-adventures.com/)
|
||||
|
||||
## Task: Nvim macros
|
||||
|
||||
In this task, we will learn about the power of macros in Neovim.
|
||||
|
||||
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 `nvim`.
|
||||
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: `]`
|
||||
|
||||
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.
|
||||
|
|
254
src/day_5/notes.md
Normal file
254
src/day_5/notes.md
Normal file
|
@ -0,0 +1,254 @@
|
|||
# Notes
|
||||
|
||||
## Neovim
|
||||
|
||||
- `: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)
|
||||
|
||||
## Regular expressions (Regex)
|
||||
|
||||
Can be used for example with `grep`, `rg`, `find`, `fd`, `nvim`, etc.
|
||||
|
||||
`^`: Start of line
|
||||
`$`: End of line
|
||||
`()`: Group
|
||||
`[abcd]`: Character set, here `a` until `d`
|
||||
`[a-z]`: Character range, here `a` until `z`
|
||||
`[^b-h]`: Negated character range, here `b` to `h`
|
||||
`.`: Any character
|
||||
`.*`: 0 or more characters
|
||||
`.+`: 1 or more characters
|
||||
`\w`: Word
|
||||
`\w`: Not word
|
||||
`\d`: Digit
|
||||
`\d`: Not digit
|
||||
`\s`: Whitespace
|
||||
`\s`: Not whitespace
|
||||
|
||||
## More tools
|
||||
|
||||
### Curl
|
||||
|
||||
We did use `curl`, but not yet for downloading.
|
||||
|
||||
```bash
|
||||
# Download file into current directory while using the default name
|
||||
curl -L LINK_TO_FILE -O
|
||||
|
||||
# Download file while giving the path to save the file into
|
||||
# (notice that we are using small o now, not O)
|
||||
curl -L LINK_TO_FILE -o PATH
|
||||
```
|
||||
|
||||
`-L` tells `curl` to follow redirections (for example from `http` to `https`).
|
||||
|
||||
### cut
|
||||
|
||||
Demo file `demo.txt`:
|
||||
|
||||
```
|
||||
here,are,some
|
||||
comma,separated,values
|
||||
de mo,file,t x t
|
||||
```
|
||||
|
||||
```bash
|
||||
# Get the N-th column by using SEP as separator
|
||||
cut -d SEP -f N FILE
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```console
|
||||
$ cut -d "," -f 1 demo.txt
|
||||
here
|
||||
comma
|
||||
de mo
|
||||
```
|
||||
|
||||
You can also pipe into `cut` instead of specifying `FILE`.
|
||||
|
||||
### sed
|
||||
|
||||
```bash
|
||||
# Substitute
|
||||
sed 's/OLD/NEW/g' FILE
|
||||
|
||||
# Delete line that contains PATTERN
|
||||
sed '/PATTERN/d' FILE
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```console
|
||||
$ 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
|
||||
```
|
||||
|
||||
You can also pipe into `sed` instead of specifying `FILE`.
|
||||
|
||||
When you specify `FILE`, you can use the option `-i` to operate _inplace_. This means that the file is modified directly.
|
||||
|
||||
### find
|
||||
|
||||
```bash
|
||||
# Find everything ending with `.sh` of type file `f` using globbing
|
||||
find . -type f -name '*.sh'
|
||||
|
||||
|
||||
# Using regex
|
||||
find . -type f -regex '.+\.sh'
|
||||
```
|
||||
|
||||
### xargs
|
||||
|
||||
```bash
|
||||
# Show the content of all files starting with '*.sh'
|
||||
find . -type f -name '*.sh' | xargs cat
|
||||
```
|
||||
|
||||
### ripgrep
|
||||
|
||||
```console
|
||||
$ rg '.*,(.*),.*' -r '$1' demo.txt
|
||||
```
|
||||
|
||||
## Symlinks
|
||||
|
||||
```bash
|
||||
# Soft link
|
||||
ln -s SRC_PATH DEST_PATH
|
||||
|
||||
# Hard link
|
||||
ln SRC_PATH DEST_PATH
|
||||
```
|
||||
|
||||
## Poetry
|
||||
|
||||
```bash
|
||||
# Initialize environment
|
||||
poetry init
|
||||
|
||||
# Add package to the environment
|
||||
poetry add PACKAGENAME
|
||||
|
||||
# Remove package from environment
|
||||
poetry remove PACKAGENAME
|
||||
|
||||
# Update
|
||||
poetry update
|
||||
|
||||
# Enter environment
|
||||
poetry shell
|
||||
```
|
||||
|
||||
It is important to write `#!/usr/bin/env python3` instead of `#!/usr/bin/python3` in your scripts to be able to use them in an environment.
|
||||
|
||||
## 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/(...)')
|
||||
```
|
105
src/day_5/tasks.md
Normal file
105
src/day_5/tasks.md
Normal file
|
@ -0,0 +1,105 @@
|
|||
# Tasks
|
||||
|
||||
## Task: Neovim macros
|
||||
|
||||
In this task, we will learn about the power of macros in Neovim.
|
||||
|
||||
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 `nvim`.
|
||||
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: `]`
|
||||
|
||||
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.
|
||||
|
||||
## 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 hight) 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!
|
||||
|
||||
## Task: Ripgrep
|
||||
|
||||
The following website uses a PDF file but it does not let you see download it: [https://knowunity.de/knows/biologie-neurobiologie-1c6a4647-4707-4d1b-8ffb-e7a750582921](https://knowunity.de/knows/biologie-neurobiologie-1c6a4647-4707-4d1b-8ffb-e7a750582921)
|
||||
|
||||
Know that you are kind of a "hacker", you want to use a workaround.
|
||||
|
||||
Use pipes `|`, `curl`, `rg` (ripgrep) and `xargs` to parse the HTML of the website, extract the link to the PDF file and download the file.
|
||||
|
||||
The link to the PDF file starts with `https://` and ends with `.pdf`.
|
||||
|
||||
After that it works, write a script that asks the user for the link to a document at [knowunity.de](https://knowunity.de) and downloads the PDF file.
|
||||
|
||||
## Task: Cows everywhere!
|
||||
|
||||
[![](https://imgs.xkcd.com/comics/tar_2x.png)](https://xkcd.com/1168/)
|
||||
|
||||
Download the source code of this book using `curl` as a `tar.gz` archive: [https://codeberg.org/Mo8it/How\_To\_Linux/archive/main.tar.gz](https://codeberg.org/Mo8it/How_To_Linux/archive/main.tar.gz)
|
||||
|
||||
We are not using Git at this point to practice dealing with archives.
|
||||
|
||||
Extract the files from the archive! (_Don't worry, you have more than 10 seconds_)
|
||||
|
||||
Use `find` to find all Markdown files (ending with `.md`). Then use `sed` to replace every match of `echo` with `cowsay` in the files found.
|
||||
|
||||
Why? Easy: Why not?
|
||||
|
||||
## Task: Lazygit
|
||||
|
||||
In this task, you will learn using Lazygit.
|
||||
|
||||
1. Install Lazygit. Follow the instructions for Fedora on [github.com/jesseduffield/lazygit](https://github.com/jesseduffield/lazygit). You might need to install `dnf-plugins-core` first to be able to add something via _COPR_ (Cool Other Package Repo).
|
||||
1. Put the files and directories that you did create during the course into a directory.
|
||||
1. Go into the directory.
|
||||
1. Run `lazygit`. It will initialize a git repository in this directory if none already exists. Confirm the initialization. Starting with now, every git operation should be done in Lazygit.
|
||||
1. Add everything as staged.
|
||||
1. Commit.
|
||||
1. Create a repository on [git.mo8it.xyz](https://git.mo8it.xyz).
|
||||
1. Add the new remote.
|
||||
1. Push to the new remote.
|
||||
1. Modify a file (or multiple files).
|
||||
1. Verify your changes in Lazygit, stage, commit and push.
|
||||
|
||||
## Task: Click
|
||||
|
||||
If you are done with all tasks and still have time, read about the Python package `click` that enables you to write your own CLI programs!
|
||||
|
||||
Click is not installed by default. You need to install it with `poetry`.
|
||||
|
||||
Write a CLI with some commands and subcommands.
|
||||
|
||||
Don't forget to write useful help messages!
|
Loading…
Reference in a new issue