DEV Community

Cover image for Shell tools and scripting — missing semester notes
Sylwia Vargas
Sylwia Vargas

Posted on

Shell tools and scripting — missing semester notes

These are my notes from the MIT's The Missing Semester of Your CS Education.


Lecture 2: Shell Tools and Scripting

Echo and interpolation 🤖

  • echo will take as many arguments as you want and will treat each space as a beginning of new argument; for that reason, you can pass arguments as:
    • echo Hello World (which will introduce new lines)
    • echo Hello\World (one line)
    • echo "Hello World" (one line)
    • echo 'Hello World' (one line)
  • declaring variables happens with no spaces: name=Sylwia; you invoke the variable with a dollar sign: $name
  • you can interpolate the value of the variable with double quotes:
  name=Sylwia
  echo $name #Sylwia
  echo "My name is $name" #My name is Sylwia
  echo 'My name is $name' #My name is $name
Enter fullscreen mode Exit fullscreen mode
  • you can save an output of a command to a variable, e.g.:
  date=$(date)
  echo "today is $date" # today is Fri Nov 20 13:34:55 EST 2020
Enter fullscreen mode Exit fullscreen mode

Variables 📝

  • $0 stands for the name of the script
  • $# - number of arguments passed in
  • $$ - pid (process id) of this command
  • $1 (up to $9) - the first (ninth) element in a collection
  • $@ - all the arguments
  • $? — error code from the previous command, e.g.
echo "Hello" #Hello
$? #0 because everything went well
mkdir test
!! #mkdir test; mkdir: test: File exists
echo $? #1
true 
echo $? #0 because true always evaluates to no errors
false 
echo $? #1
Enter fullscreen mode Exit fullscreen mode
  • $_ — last argument of the previous command
  • !! — repeats the last command (e.g. sudo !! will pass the last command as an argument to sudo)

Logical operators 🤓

  • || — it prints the left-hand side if it's true, otherwise, the right-hand side will print;
  • && — it prints if both sides are true;
  • ; - will print no matter what
  • -ne - comparison operator (non-equal)

Searching and finding 👀

  • ls *.sh - an example of globbing; lists any file that has this combination of letters
  • ls ?.sh - looks for any file that has just one character before the .sh
  • ls -R will list all the files recursively
  • find . -name src -type d - recursively find in the current folder a file with a name of "src" and the type of "directory"
  • find . -path '**/test/*.py' -type f - find in the current folder all the files that are in any /test subfolder located in any subfolder
  • find . -mtime -1 finds all the files that have been modified in the last day
  • find . -name "*.tmp" -exec rm {} \; - find all files with the .tmp ending execute removal
  • fd . -name "*.tmp" - uses regex for looking for files and ignores git files
  • 🚨 grep -R foobar . - looks for examples of foobar in all the files in this directory
  • ripgrep - same but nicely-formatted and you can get a few lines of context

History 📙

  • ctrl + r - reverse search
  • history — shows all command history
  • history 1 - shows last command
  • history 100 | grep ls - shows all commands in the last 100 command history entries that contained "ls"

Misc 🧀

  • convert image.{png,jpg} - same as convert image.png image.jpg
  • touch foo{,1,2,3} will create 4 files (foo, foo1, etc.)
  • touch project{1,2}/main/foo{,1,2} will create 6 files (3 in each path)
  • touch {foo,bar}/{a..j} will create a to j files in both dirs
  • #!/usr/local/python gives the shell path to execute a command in another language; you could achieve the same with #!/usr/bin/env python (if you don't know where it lives)
  • shellcheck is a debugging tool for scripting; it takes an argument of a file

Cover photo by energepic.com from Pexels

Top comments (4)

Collapse
 
timmybytes profile image
Timothy Merritt

Variables 📝
$0 stands for the name of the script
$# - number of arguments passed in
$$ - pid (process id) of this command
$1 (up to $9) - the first (ninth) element in a collection
$@ - all the arguments
$? — error code from the previous command, e.g.

Awesome write-up! I’ve been knee deep in bash’s positional parameters all week.

To add to this already thorough list, $* creates one combined argument separated by the $IFS character (default is a space), while $@ acts like an array of each individual argument (which, as you mention, can be isolated further by accessing them in order from $1 to $9, but also beyond that by adding braces ${10}, ${11} ...).

For example (taken from here):

# testvar 
for i in "$@"; do echo "@ '$i'"; done
for i in "$*"; do echo "* '$i'"; done
Enter fullscreen mode Exit fullscreen mode

Would print the following with multiple arguments:

./testvar foo bar baz 'long arg'
@ 'foo'
@ 'bar'
@ 'baz'
@ 'long arg'
* 'foo bar baz long arg'
Enter fullscreen mode Exit fullscreen mode

So if you’re trying to iterate over arguments individually, use $@, whereas if you’re trying to do something with the group of arguments as a single whole, use $*.

Collapse
 
sylwiavargas profile image
Sylwia Vargas

Ohhhh, this is super interesting and helpful. Thank you for taking the time to write the comment and for sharing the link - I’m going to check it out!

Collapse
 
timmybytes profile image
Timothy Merritt

My pleasure! Bash can be really obtuse sometimes, but it's a powerful command language, and you can especially do a lot with these positional parameter arguments depending on how you set up your scripts. Happy hacking!

Collapse
 
rmhogervorst profile image
Roel Hogervorst

Nice overview!