14. How can I automate things with bash?#
So far we have used bash commands to navigate our file system as a way to learn about the file system itself. To do this we used commands like:
mv
cd
pwd
ls
find
rm
Bash is a unix shell for the GNU operating system and it has been adopted in other contexts as well. It is the default shell on Ubuntu linux as well for example (and many others). This is why we teach it.
A Unix shell is both a command interpreter and a programming language. As a command interpreter, the shell provides the user interface to the rich set of GNU utilities. The programming language features allow these utilities to be combined.
Read the official definition of bash
and a shell in the bash manual
14.1. Inspecting an example script#
Today we will start by inspecting the github action file, first we’ll navigate to the folder.
cd kwl-sp24-brownsarahm/
Next we’ll look at which files we have
ls .github/workflows/
create_about.yml experiencereport.yml getassignment.yml
experienceinclass.yml forgottenexperience.yml
Then we will look at the getassignmet one.
cat .github/workflows/getassignment.yml
name: Create badge issues (Do not run manually)
on:
workflow_dispatch
# once you edit, change the name
jobs:
check-contents:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
# Install dependencies
- name: Set up Python 3.9
uses: actions/setup-python@v4
with:
python-version: 3.9
- name: Install Utils
run: |
pip install git+https://github.com/introcompsys/courseutils@main
- name: Get badge requirements
run: |
# prepare badge lines
pretitle="prepare-"$(sysgetbadgedate --prepare)
sysgetassignment --type prepare | gh issue create --title $pretitle --label prepare --body-file -
# review badge lines
rtitle="review-"$(sysgetbadgedate --review)
sysgetassignment --type review | gh issue create --title $rtitle --label review --body-file -
# practice badge lines
pratitle="practice-"$(sysgetbadgedate --practice)
sysgetassignment --type practice| gh issue create --title $pratitle --label practice --body-file -
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# edit the run step above for the level(s) you want.
# You should keep the prepare, because they are required for experience badges
# You may choose to get only the review or only the practice (and change this any time)
14.2. Variables in Bash#
We can create variables
MYVAR="my_val"
notice that there are no spaces around the =
. spaces in bash separate commands and options, so they cannot be in variable declarations.
and use them with a $
before the variable name.
echo $MYVAR
This variable is local, in memory, to the current terminal window, so if we open a separate window and try echo $NAME
it will not work. We can also see that it does not create any file changes.
my_val
A common mistake is to put a space around the =
sign, this is actually considered good style in many other languages.
NAME = "Sarah"
-bash: NAME: command not found
In bash, however, this creates an error. When there is a space after NAME
, bash
tried to interpet NAME
as a bash command, but then it does not find it, so it gives an error.
Removing the space works again:
NAME="Sarah"
echo $NAME
Sarah
echo $NAME
Sarah
The $
is essential syntax for recalling variables in bash. If we forget it, it treats it as a literal
echo NAME
echo NAME
NAME
so we get the variable name out instead of the variable value
14.3. Environment Variables#
Environment variables are global.
A common one is the PATH
echo $PATH
/Users/brownsarahm/anaconda3/bin:/Users/brownsarahm/anaconda3/condabin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/TeX/texbin
mine has my anaconda install, yours may be different
You can store environment variables to be set each time you start a terminal in your profile.
On MacOS this file is:
~/.bash_profile
on linux it is
~/.baschrc
cat ~/.bash_profile
alias pip=pip3
alias python=python3
export PS1="\u@\W $ "
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/Users/brownsarahm/anaconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
else
if [ -f "/Users/brownsarahm/anaconda3/etc/profile.d/conda.sh" ]; then
. "/Users/brownsarahm/anaconda3/etc/profile.d/conda.sh"
else
export PATH="/Users/brownsarahm/anaconda3/bin:$PATH"
fi
fi
unset __conda_setup
# <<< conda initialize <<<
A common one you might want to set is:
PS1
the primary prompt line. Content you can use is documented in the gnu docsalias
lets you set another name for a program, for exmaple I usepip
to callpip3
14.4. Bash Loops#
We can also make loops like
for loopvar in list
do
# loop body
echo $loopvar
done
So, for example:
for name in Sarah Cam Kai
> do
> echo $name
> done
Notes:
The
>
is not typed, it is what happens since the interpreter knows that after we write the first line, the command is not complete.a list in bash is items with spaces, no brackets here (
Sarah Cam Kai
)
Sarah
Cam
Kai
and this does as expected
When we get the command back with the up arrow key, it puts it all on one line, because it was one command. The ;
(semicolon) separates the “lines”
for name in Sarah Cam Kai; do echo $name; done
Sarah
Cam
Kai
14.5. Nesting commands#
Let’s look at the action file again
name: Create badge issues (Do not run manually)
on:
workflow_dispatch
# once you edit, change the name
jobs:
check-contents:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
# Install dependencies
- name: Set up Python 3.9
uses: actions/setup-python@v4
with:
python-version: 3.9
- name: Install Utils
run: |
pip install git+https://github.com/introcompsys/courseutils@main
- name: Get badge requirements
run: |
# prepare badge lines
pretitle="prepare-"$(sysgetbadgedate --prepare)
sysgetassignment --type prepare | gh issue create --title $pretitle --label prepare --body-file -
# review badge lines
rtitle="review-"$(sysgetbadgedate --review)
sysgetassignment --type review | gh issue create --title $rtitle --label review --body-file -
# practice badge lines
pratitle="practice-"$(sysgetbadgedate --practice)
sysgetassignment --type practice| gh issue create --title $pratitle --label practice --body-file -
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# edit the run step above for the level(s) you want.
# You should keep the prepare, because they are required for experience badges
# You may choose to get only the review or only the practice (and change this any time)
We can run a command to generate the list by putting it inside $()
to run that command first. Think kind of like PEMDAS and the $
in bash is for variables.
This is useful in combination with the the loop
for file in $(ls)
> do
> echo $file
> done
README.md
community_contributions.md
experiences
the $()
tells bash to run that command first and then hold its output as a variable for use elsewhere
If we modify it
for file in $(ls -a); do echo $file ; done
.
..
.git
.github
.templates
README.md
community_contributions.md
experiences
test hello
14.6. Conditionals in bash#
We can also do conditional statements
if test -f .git
> then
> echo "file"
> fi
the key parts of this:
test
checks if a file or directory existsthe
-f
option makes it check if the item is a filewhat to do if the condition is met goes after a
then
keywordthe
fi
(backwardsif
) closes the if statment
This returns nothing because it is not a file
If we switch it, we get output:
if test -f README.md; then echo "file"; fi
file
We can put the if inside of the loop.
if test .git; then echo "exists"; fi
exists
echo $(test hello)
for file in $(ls -a); do if test -f $file ;then echo $file; fi ; done
README.md
community_contributions.md
14.7. Script files#
We can put our script into a file
nano filecheck.sh
So that the file
cat filecheck.sh
for file in $(ls)
do
if test -f $file
then
echo $file
fi
done
and run it with bash <filename>
bash filecheck.sh
README.md
community_contributions.md
filecheck.sh
cd ../
ls
ex spring2024
gh-inclass-sp24-brownsarahm test
kwl-sp24-brownsarahm tiny-book
cd spring2024/
14.8. Prepare for Next Class#
Review your idethoughts.md
from a few weeks ago and add some summary notes.
14.9. Badges#
Update your KWL Chart learned column with what you’ve learned
Write a bash script that updates your badges.json file and then generates your progress report using courseutils we will use this in lab on 3/25
Update your KWL Chart learned column with what you’ve learned
Write a bash script that updates your badges.json file and then generates your progress report using courseutils we will use this in lab on 3/25
Update your action file for getting assignments to use the new courseutils (at compsys-progtools instead of introcompsys)
14.10. Experience Report Evidence#
14.11. Questions After Today’s Class#
14.11.1. What parts of the terminal are saved local per window and what parts aren’t?#
local variables local, but there are also global variables
most programs should be per window.
14.11.2. Are there functions in bash scripting?#
Yes see the docs
14.11.3. what is YMAL syntax similar to in terms of other programming langauges#
It is kind of like a dicionary, but yaml is just a file type, like json or xml, not a a programming language. It is a way to store data that is parse-able.
14.11.4. What kind of action could be useful?#
Anything you might do a alot and would prefer to have automated. Fore xample in calss we have the actions for the badges, the market place has examples.
there are also the ideas in the discussions.
14.11.5. How to stop a loop (break statement)#
break
exists in bash
14.11.6. How to check values (greater than/less than)#
14.11.7. What differentiates a terminal and a shell?#
a shell is the language/interpreter terminal is how you access it.
Sometimes they collapse like powershell is a terminal and shell.
14.11.8. How can I change the experience workflow to automatically fill in the date?#
This is nontrival because you would need to edit the file instead of just copying it. It is a good build badge.