19 KiB
Scripting
Bash
A bash
script is a sequence of command that are executed one by one.
Most of the time we just execute one command and wait for the result to then make a decision and execute an other command.
We can however create a sequence of commands on the command line.
(baseline-) ➜ ~ echo hello world
hello world
(baseline-) ➜ ~ date
Wed 16 Mar 2022 07:06:02 PM CET
(baseline-) ➜ ~ cal
March 2022
Su Mo Tu We Th Fr Sa
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
(baseline-) ➜ ~ echo hello world date cal
hello world date cal
(baseline-) ➜ ~ echo hello world; date; cal
hello world
Wed 16 Mar 2022 07:06:19 PM CET
March 2022
Su Mo Tu We Th Fr Sa
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
A very visually similar result, but completely different operation, can be obtained by replacing the ;
with &
or &&
.
&
will launch a new process and send it to the background, &&
will evaluate the return status of your process and only continue if the status was 0
, or in other words successful.
(baseline-) ➜ ~ echo hello world & date & cal
[1] 3075524
hello world
[2] 3075525
[1] - 3075524 done echo hello world
Wed 16 Mar 2022 07:06:33 PM CET
[2] + 3075525 done date
March 2022
Su Mo Tu We Th Fr Sa
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
(baseline-) ➜ ~ echo hello world && date && cal
hello world
Wed 16 Mar 2022 07:06:40 PM CET
March 2022
Su Mo Tu We Th Fr Sa
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
(baseline-) ➜ ~
This should make you think we can create quite complicated logical flows in bash
and you're right!
But first things first, let's create our first script!
(baseline-) ➜ bash file test.sh
test.sh: Bourne-Again shell script, ASCII text executable
(baseline-) ➜ bash ls -l test.sh
-rwxr-xr-x 1 waldek waldek 39 Mar 16 19:13 test.sh
(baseline-) ➜ bash cat test.sh
#!/bin/bash
echo hello world
cal
date
(baseline-) ➜ bash ./test.sh
hello world
March 2022
Su Mo Tu We Th Fr Sa
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Wed 16 Mar 2022 07:27:22 PM CET
(baseline-) ➜ bash bash test.sh
hello world
March 2022
Su Mo Tu We Th Fr Sa
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Wed 16 Mar 2022 07:27:25 PM CET
(baseline-) ➜ bash
If you observe the output above you can conclude multiple things.
- the
test.sh
file is a simple text file - it has executable permissions for the owner, group and others
- we can execute the sequence of commands in the script in two ways
./test.sh
bash test.sh
- the content is a series of commands but with a weird first line
That first line is called a shebang and is a way of explaining which interpreter understands the lines that follow.
If you venture out into the python universe you'll encounter the same norm but with a different path to an interpretor, often /bin/python3
or /usr/bin/env python3
.
The later is a sort of shortcut that points to the local python installation, even if it's not in a standard location.
A shebang is not necessary for a script to function but is highly advised.
The env
program is actually very interesting!
Let's try it by itself.
➜ ~ env
PAGER=less
LANGUAGE=en_US:en
GNOME_TERMINAL_SCREEN=/org/gnome/Terminal/screen/022a5a78_fe95_445c_9b33_f6dcb35cfd27
LANG=en_US.UTF-8
DISPLAY=:0
SWAYSOCK=/run/user/1000/sway-ipc.1000.1565.sock
WAYLAND_DISPLAY=wayland-0
AUTOSWITCH_VERSION=3.4.0
HUSHLOGIN=FALSE
USER=waldek
OLDPWD=/home/waldek/bin/bash
HOME=/home/waldek
MOZ_ENABLE_WAYLAND=1
VIRTUAL_ENV=/home/waldek/.virtualenvs/baseline-
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-acMe3wyyoo,guid=ad1233c6039551be866f78ae61f911b2
XDG_VTNR=1
XDG_SEAT=seat0
I3SOCK=/run/user/1000/sway-ipc.1000.1565.sock
LESS=-R
_=/usr/bin/env
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.webp=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
AUTOSWITCH_DEFAULTENV=baseline
VTE_VERSION=6203
LSCOLORS=Gxfxcxdxbxegedabagacad
ZSH=/home/waldek/.oh-my-zsh
AUTOSWITCH_FILE=.venv
MAIL=/var/mail/waldek
LOGNAME=waldek
PS1=(baseline-) %(?:%{%}➜ :%{%}➜ ) %{$fg[cyan]%}%c%{$reset_color%} $(git_prompt_info)
GDK_BACKEND=wayland
PATH=/home/waldek/.virtualenvs/baseline-/bin:/home/waldek/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/home/waldek/.local/bin:/home/waldek/bin/python/:/home/waldek/.local/bin:/home/waldek/bin/python/
XDG_RUNTIME_DIR=/run/user/1000
QT_QPA_PLATFORM=wayland
XDG_SESSION_ID=2
XDG_SESSION_TYPE=wayland
FPATH=/home/waldek/.oh-my-zsh/functions:/home/waldek/.oh-my-zsh/completions:/home/waldek/.oh-my-zsh/cache/completions:/home/waldek/.oh-my-zsh/custom/plugins/autoswitch_virtualenv:/home/waldek/.oh-my-zsh/plugins/git:/home/waldek/.oh-my-zsh/functions:/home/waldek/.oh-my-zsh/completions:/home/waldek/.oh-my-zsh/cache/completions:/usr/local/share/zsh/site-functions:/usr/share/zsh/vendor-functions:/usr/share/zsh/vendor-completions:/usr/share/zsh/functions/Calendar:/usr/share/zsh/functions/Chpwd:/usr/share/zsh/functions/Completion:/usr/share/zsh/functions/Completion/AIX:/usr/share/zsh/functions/Completion/BSD:/usr/share/zsh/functions/Completion/Base:/usr/share/zsh/functions/Completion/Cygwin:/usr/share/zsh/functions/Completion/Darwin:/usr/share/zsh/functions/Completion/Debian:/usr/share/zsh/functions/Completion/Linux:/usr/share/zsh/functions/Completion/Mandriva:/usr/share/zsh/functions/Completion/Redhat:/usr/share/zsh/functions/Completion/Solaris:/usr/share/zsh/functions/Completion/Unix:/usr/share/zsh/functions/Completion/X:/usr/share/zsh/functions/Completion/Zsh:/usr/share/zsh/functions/Completion/openSUSE:/usr/share/zsh/functions/Exceptions:/usr/share/zsh/functions/MIME:/usr/share/zsh/functions/Math:/usr/share/zsh/functions/Misc:/usr/share/zsh/functions/Newuser:/usr/share/zsh/functions/Prompts:/usr/share/zsh/functions/TCP:/usr/share/zsh/functions/VCS_Info:/usr/share/zsh/functions/VCS_Info/Backends:/usr/share/zsh/functions/Zftp:/usr/share/zsh/functions/Zle:/usr/share/zsh:/usr/share/zsh
SHELL=/usr/bin/zsh
AUTOSWITCH_SILENT=1
EDITOR=vim
MOTD_SHOWN=pam
SHLVL=2
GNOME_TERMINAL_SERVICE=:1.10
COLORTERM=truecolor
XCURSOR_SIZE=24
TERM=xterm-256color
PWD=/home/waldek
XDG_SESSION_CLASS=user
➜ ~
What is all of this? Well, the are the current environment variables defined in your shell. You'll probably recognize some of them. Let's play around with what we have defined.
➜ ~ echo SHELL
SHELL
➜ ~ echo $SHELL
/usr/bin/zsh
➜ ~ echo $USER
waldek
➜ ~ echo $HOME
/home/waldek
➜ ~ echo $
zsh: do you wish to see all 223 possibilities (56 lines)?
Yes, tab complete works! Your variables will be slightly different but that's not an issue at all.
➜ ~ echo $
! EUID MAILPATH SWAYSOCK
# fg manpath TERM
* FG MANPATH termcap
- fg_bold module_path terminfo
? fg_no_bold MODULE_PATH TIMEFMT
@ fignore modules TMPPREFIX
_ FIGNORE MOTD_SHOWN TRY_BLOCK_ERROR
$ fpath MOZ_ENABLE_WAYLAND TRY_BLOCK_INTERRUPT
0 FPATH nameddirs TTY
aliases funcfiletrace NULLCMD TTYIDLE
ARGC FUNCNEST OLDPWD UID
argv funcsourcetrace OPTARG USER
AUTOSWITCH_DEFAULTENV funcstack OPTIND userdirs
AUTOSWITCH_FILE functions options usergroups
AUTOSWITCH_SILENT functions_source OSTYPE USERNAME
AUTOSWITCH_VERSION functrace PAGER VENDOR
bg FX parameters VIRTUAL_ENV
BG galiases patchars VTE_VERSION
bg_bold GDK_BACKEND _patcomps watch
bg_no_bold GID path WATCH
bold_color GNOME_TERMINAL_SCREEN PATH WATCHFMT
builtins GNOME_TERMINAL_SERVICE pipestatus WAYLAND_DISPLAY
cdpath histchars plugins widgets
CDPATH HISTCHARS _postpatcomps WORDCHARS
color HISTCMD PPID XCURSOR_SIZE
COLORTERM HISTFILE precmd_functions XDG_RUNTIME_DIR
colour history preexec_functions XDG_SEAT
COLUMNS historywords prompt XDG_SESSION_CLASS
commands HISTSIZE PROMPT XDG_SESSION_ID
_compautos HOME PROMPT2 XDG_SESSION_TYPE
_comp_dumpfile HOST PROMPT3 XDG_VTNR
COMPLETION_WAITING_DOTS HUSHLOGIN PROMPT4 zle_bracketed_paste
_comp_options I3SOCK PS1 ZLS_COLORS
comppostfuncs jobdirs PS2 ZSH
compprefuncs jobstates PS3 ZSH_ARGZERO
_comps jobtexts PS4 ZSH_CACHE_DIR
_comp_setup key psvar ZSH_COMPDUMP
CPUTYPE KEYBOARD_HACK PSVAR ZSH_CUSTOM
d keymaps PWD zsh_eval_context
DBUS_SESSION_BUS_ADDRESS KEYTIMEOUT QT_QPA_PLATFORM ZSH_EVAL_CONTEXT
debian_missing_features LANG RANDOM ZSH_NAME
dirstack langinfo READNULLCMD ZSH_PATCHLEVEL
dis_aliases LANGUAGE reset_color zsh_scheduled_events
dis_builtins _lastcomp reswords ZSH_SUBSHELL
dis_functions LESS saliases ZSH_THEME
dis_functions_source LINENO __savecursor ZSH_THEME_GIT_PROMPT_CLEAN
dis_galiases LINES SAVEHIST ZSH_THEME_GIT_PROMPT_DIRTY
dis_patchars LISTMAX SCREEN_NO ZSH_THEME_GIT_PROMPT_PREFIX
DISPLAY LOGCHECK __searching ZSH_THEME_GIT_PROMPT_SUFFIX
dis_reswords LOGNAME _services ZSH_THEME_RUBY_PROMPT_PREFIX
dis_saliases LS_COLORS SHELL ZSH_THEME_RUBY_PROMPT_SUFFIX
EDITOR LSCOLORS SHLVL ZSH_THEME_RVM_PROMPT_OPTIONS
EGID MACHTYPE SHORT_HOST ZSH_THEME_TERM_TAB_TITLE_IDLE
EPOCHREALTIME MAIL signals ZSH_THEME_TERM_TITLE_IDLE
EPOCHSECONDS MAILCHECK SPROMPT ZSH_VERSION
epochtime mailpath status
➜ ~ echo $
We can create our own variables as follows. Notice how an undefined variable does not throw an error. This is very typical for shell scripting, python on the other hand would crash over an undefined variable.
waldek@helloworld:~$ echo $USER
waldek
waldek@helloworld:~$ echo $name
waldek@helloworld:~$ name="wouter gordts"
waldek@helloworld:~$ echo $name
wouter gordts
waldek@helloworld:~$
If you open up a new shell this $name
variable will not be defined because variables are local to each instance of bash
that is running.
This can be observed as follows.
waldek@helloworld:~$ name="wouter gordts"
waldek@helloworld:~$ echo $name
wouter gordts
waldek@helloworld:~$ bash
waldek@helloworld:~$ echo $name
waldek@helloworld:~$ exit
exit
waldek@helloworld:~$ export name
waldek@helloworld:~$ bash
waldek@helloworld:~$ echo $name
wouter gordts
waldek@helloworld:~$ exit
exit
waldek@helloworld:~$
What is a Bash Script - What are they, how do they work and how to run them.
Variables - Store data temporarily for later use.
Write a program that prints information about your computer such as:
- the hostname
- the FQDN
- number of cpus
- type of cpu
- amount of RAM
Write a program that prints information about a given user such as:
- name
- UID
- their default shell
- groups they are a member of
- number of files in their home directory
- amount of disk space they use
Input - Different ways to supply data and directions to your Bash script.
Arithmetic - Perform various arithmetic operations in your Bash script.
If Statements - How to make decisions within your Bash script.
Write a script that takes one argument which is a filepath. The program should print out what type of file this is, and if it is readable, print the first and last 5 lines.
Loops - A variety of ways to perform repetitive tasks.
Write a script that sets all you cpu's to a desired governor.
Functions - Reuse code to make life easier.
User Interface - Make your scripts user friendly.
Python
This repository has a twenty day course to learn python written by me. The main file you need to follow is this one. Some practical exercises can be found here together with the needed source files.
Vim as an IDE
I made a tutorial on the essentials of vim customization. My real world configuration can be found at this repository.