Skip to content

Instantly share code, notes, and snippets.

@adamhl8
Last active September 9, 2023 04:35
Show Gist options
  • Save adamhl8/57e9f429e9a6a272fb89293b6d3f5258 to your computer and use it in GitHub Desktop.
Save adamhl8/57e9f429e9a6a272fb89293b6d3f5258 to your computer and use it in GitHub Desktop.
Shell/Command Line Lesson Notes

Shell/Command Line Lesson Notes

Command Line "Magic"

"What's the difference between a terminal and a shell?"

A terminal is the computer application you open (e.g. macOS Terminal, iTerm, etc). You need some kind of terminal app to be able to interact with a shell.

  • These are technically called "terminal emulators". They emulate the old-school physical terminals that allowed you to interact with "shell-like" operating systems like MS-DOS.
  • More specifically, terminal emulators take your input and forward it to the underlying program (which is generally the shell).
    • The terminal is like a car's dashboard while the shell is like the engine.

A shell is the actual program that interprets/processes your input. e.g. zsh, bash, ash, sh, etc. On your MacBook, you are using the zsh shell within the Terminal (or maybe iTerm) application.

  • Also known as a command line interpreter/command language interpreter.
  • One of the main purposes of a shell is to simply find and execute other programs (e.g. git).
  • Shells also provide a built-in programming language (command language) that provides things like control flow, comparison operators, etc.
    • So for example there's "bash" the shell program, and "bash" the language.

See: https://dwmkerr.com/effective-shell-part-5-understanding-the-shell/images/diagram3-terminal-and-shell.png

Further reading: https://unix.stackexchange.com/questions/4126/what-is-the-exact-difference-between-a-terminal-a-shell-a-tty-and-a-con

"What is POSIX?"

https://en.wikipedia.org/wiki/POSIX

Simply put, POSIX is a standard created by IEEE that defines what APIs/programs should exist and how they function in order to create a consistent experience across operating systems.

POSIX-certified vs. POSIX-compliant: https://en.wikipedia.org/wiki/POSIX#POSIX-certified

When looking up how to do something in a shell, you'll often see a "POSIX" way of doing it, which means it will most likely work regardless of the OS or shell you're using.

POSIX Shell & Utilities: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html

POSIX Shell Command Language: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html

"Where do commands like cat and less come from?"

cat, less, and most of the commands you run are programs.

Enter type cat into your terminal. This will tell you the location of the given program.

Point being, these programs don't just magically exist, they are actual files/programs that you are executing by typing the name of the file.

Shells are just programs too. type zsh will tell you the location of the zsh file/executable/program.

cd into the folder that contains cat (find the folder with type cat). You should see a bunch of other programs, some of which you will probably recognize.

"What about type? Is that a program?"

See what happens if you enter type type. It should tell you it's a shell built-in.

A shell built-in is a function of a given shell (e.g. zsh). It exists within the zsh program itself.

For example, cd is also a shell built-in. That means every shell (zsh, bash, etc) technically has its own implementation of cd.

A "command" is a bit of a misnomer; pretty much anything you run in a command line is either a program or a shell built-in.

"Wait, so why can I run cat from anywhere?"

cat is (usually) in the /usr/bin/ directory. This directory is on your path.

Enter echo $PATH. This is your system's path, which is simply a list of directories.

Any executable within any directory on your path is accessible from anywhere.

You can add directories to your path, so you could have your own bin directory somewhere and if you wanted executables within that directory to be globally available, all you have to do is add your new bin directory to the path. (Lots of ways to do this, I recommend you google it.)

So when you enter something into your shell, the shell first checks if it has a built-in function of that name. If not, it iterates through PATH until it finds a match.

This means the first match found will be executed, so the order of the directories in PATH can matter.

How to figure out how to use command line programs/tools

Most programs have a --help flag. For example, enter cat --help. It will tell you how you can use cat.

Not every program has a --help flag.

Use man (short for manual) instead. e.g. man cat.

man can sometimes be more comprehensive, but generally --help and man will contain the same info.

Further reading: https://seb.jambor.dev/posts/cd-is-not-a-program/ (I highly recommend you read this, it has some really good info.)

Shell Scripting

"How do I chain commands?"

You can use the && operator.

For example, echo hello && echo goodbye

Anything after the && will only run if the previous command ran successfully.

Try running ehco hello && echo goodbye. (The first echo is misspelled.)

Exit Status

Whenever a command finishes/exits, it always exits with a status. 0 means the program executed sucessfully. Anything other than 0 is an error.

A non-zero exit status does not necessarily mean the program crashed or anything. A program can choose to emit whatever exit code they want for whatever reason.

You can view the status of the last command that was run by doing echo $STATUS (or echo $status on zsh).

Variables

Just like in programming, within your shell you can store values (strings) in variables. (Also, shell scripting is programming.)

  • In most shells, everything is a string. That is, echo hello and echo "hello" are equivalent.
  • Variables are case-sensitive.
  • Quotes are important in certain situations. That's something we'll cover later.

Create a variable: hello="Hello World!"

You must reference variables with the $ character.

echo $hello will work. echo hello will not. (It prints "hello", but not your variable.)

"How do I write a script?"

Create a new file called hello.sh: nano hello.sh

  • Generally scripts will end in .sh, but file extensions don't matter to the shell and most shell programs.
  • In this script we implement a flag called -b to make it say "Bye" instead.

Arguments to a script can be referenced by number.

  • So $1 refers to the first argument passed in, $2 the second, etc.
arg1=$1
if [ "$arg1" = "-b" ]
then
  echo "Bye"
else
  echo "Hello"
fi

Try running your script: ./hello.sh

  • Remember, ./hello.sh is saying "look inside the current directory for hello.sh". hello.sh is looking for a globally available command named hello.sh.

By default, files are not executable.

Make it executable using chmod: chmod +x hello.sh

  • chmod is a program that allows you to change file permissions.
  • +x allows the file to be executed.

You should be able to run your script now.

test and [

The [ "$arg1" = "-b" ] syntax isn't special.

[ is just a command (usually a shell builtin). It's an alias for test.

[ "$arg1" = "-b" ] is equivalent to test "$arg1" = "-b".

"$arg1" is the first argument for [, = the second, etc.

if doesn't have to be used with test/[. if simply looks at the exit status of a command.

For example, you could do something like this:

if cp ./hello.sh ./hello2.sh
then
  echo "Copy succeeded"
else
  echo "Copy failed"
fi

One line: if cp ./hello.sh ./hello2.sh; then echo "Copy succeeded"; else echo "Copy failed"; fi

Shebangs

A shebang #! in a script tells your shell what program it should invoke the script with.

For example, if at the top of our script we put #!/bin/bash, it will run the script with bash.

If there is no shebang, the script will run using the program that executed it.

"What if I want to be able to run my script from anywhere?"

Create a directory called scripts: mkdir scripts

Move hello.sh into scripts: mv hello.sh scripts

Try running your script.

Your script isn't on path, so your shell can't find it.

Look at your current path: echo $PATH

Add your scripts directory to path: PATH="/Users/Adam/scripts:$PATH"

  • We are setting PATH equal to itself and adding our directory.

You should see your directory prepended to path: echo $PATH

Try running your script again.

Changing your path like this is not permanent, it only applies to the current shell session.

If you wanted your scripts directory to always be on path, you can add the above command to your .zshrc or equivalent.

Further reading:

Shell Scripting for Beginners

How to Add a Directory to PATH in Linux

IntelliJ Command-Line Launcher

Add /Applications/IntelliJ IDEA.app/Contents/MacOS to .zshrc:

  • path+=('/Applications/IntelliJ IDEA.app/Contents/MacOS')

.zshrc

.zshrc is a file that runs whenever you start a new zsh shell session.

This file is used for things like setting environment variables, aliases, functions, etc.

Since it's essentially a script that runs once when zsh starts up, any changes to your .zshrc won't be applied until a new session is started.

OverTheWire

OverTheWire - Game to practice command line usage

ssh [email protected] -p 2220

Make sure to logout (exit) once you're done with a level.

Resources

Linux Command Line Cheat Sheet

https://guide.bash.academy/

https://linuxcommand.org/lc3_learning_the_shell.php


https://github.com/ohmyzsh/ohmyzsh - zsh improvements/configs

https://zshthem.es


How to Use Wildcards

View a file with less

Stream a file (cat)

10 Useful Chaining Operators in Linux with Practical Examples

I/O Redirection

Piping and Redirection


What is the difference between Vi and Vim?

Opening and closing files with vi/vim

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment