The CLI isn't as scary as you think

easter egg a title screen of someone learning the cli in a classic 90s hacking style

VanJS

April 16th, 2025

Gavin Mogan

Senior Software Engineer at Digital Ocean. Digital Ocean Mascot, Sammy the Shark, holding a heart ballon

https://www.gavinmogan.com

Avatar Easter Egg

Upfront notes

  • Talking about linux. Rest are similar
  • $ is usually a shell prompt
  • Generally, Linux doesn't care what order CLI parameters are in.
  • Linux tools, like npm packages, like to do one thing and do them well.

Getting Help

Offline version

  • Most commands have a man(ual) pages
    $ man find
  • Shell functions only have help
    $ help for
  • Sometimes --help will return things
    $ ls --help

Keyboard Shortcuts

  • Ctrl+r - Reverse search through your bash history (My fav)
  • Up / Down - Prev/next in history
  • Ctrl+w - Delete previous word
  • Ctrl+k - Delete rest of line
  • Ctrl+u - Delete entire line
  • Ctrl+a - Move to start of line
  • Ctrl+e - Move to end of line

Keyboard Shortcuts

Ctrl+r - Reverse search through your bash history

Where am I?

image of northeastern universeity building

How to Change Directory

Most OSes uses forward slash - / as folder separator

Spaces and other characters should be escaped or quoted

Get back there

What is in this directory?

directory listing with a easter egg in the background for the easter egg hunt

Simple Directory Listing

$ ls

Long Listing

$ ls -l

Descending(r) by Time(t)

$ ls -ltr

Hidden files

$ ls -a

When am I?

pink easter egg

                $ TZ=America/Vancouver date
                Sun Apr 20 12:00:00 PDT 2025
              

Note: time command times a command, not time of day


                $ time sleep 30s
                sleep 30s 0.00s user 0.00s system 0% cpu 28.108 total
              

Testing HTTP

Curl and wget work kinda the same, but under different designs.

Wget is great at downloading files.

$ wget http://i.imgur.com/Ia48QDR.jpg

Curl is better at retrieving content.

$ curl https://httpcodes-8pkfp.ondigitalocean.app/json/404

Note: probably less true these days

What's happened recently?

Head will give you the first n lines

Tail will give you the last n lines

Common Options

  • -f will keep tailing
  • -F will restart tailing if file is truncated
  • -n #num# will only print out #num# number of lines

Redirection output

Output to file

$ echo "hi" > file.txt

Errors to file

$ curl http://fake.server 2> errors.txt

Output to file and console

$ echo "hi" | tee file.txt

Redirection input

Input from file

$ mysql < import.sql 
        

Wildcards (glob)

Will look find all directories that have a logs directory underneath it.

$ tail -F ~/Develop/*/logs/development.log

Will find all log files under all directories that have a log directory (one level deep)

$ tail -F ~/Develop/*/logs/*.log

Will find all log files under all directories that have a log directory (infinite levels deep)

$ tail -F ~/Develop/**/logs/*.log

Chaining

true && echo true
false || echo false
false; echo always

if and while statements

if true; then echo "its-a-me-truethy"; fi
while true; do echo "its-a-me-truethy"; done
for i in a b c; do echo $i; done

Serious wildcards

Find all directories

$ find -type d

Find all files

$ find -type f

Find all files ending in log


            $ find -name '*.log' # find all files ending in .log
            $ find -name '*.log' -exec ls {} \; # executes a command for each file
            $ find -name '*.log' -exec ls {} + # appends all files to one command
          

Run something in a directory with logs

$ find /var/log -name '*.log' -execdir pwd \;

Create Edit Update Destroy


            cat <file> # outputs contents
            tac <file> # outputs contents in reverse order
            less <file> # outputs content (controlled)
          

            rm <file> # Remove a file
            rmdir <dir> # Remove an empty directory
            mkdir <dir> # Create a directory (mkdir -p as bonus)
            # Create all the directories required to make the full path
            # (and doesn't error if already exists)
            mkdir -p <dir/subdir/subdir2>
          

            touch <file> # update timestamp/create empty file
          

Power of pipes

Mario going down a pipe and waving

With a few combos you can do anything

Grep and Awk Can Do anything


            $ grep /favicon.ico access.log
            # long output
          

            $ grep /favicon.ico access.log | awk '{print $17}'
            AppleWebKit/537.36
          

            $ grep /favicon.ico access.log | awk -F'"' '{print $6}'
            Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111
            Safari/537.36
          

For Loops


            $ for i in gavin likes pie; do mkdir $i; done
            $ ls -l
            drwxr-xr-x 2 1000 1000 4096 Apr 15 04:23 gavin
            drwxr-xr-x 2 1000 1000 4096 Apr 15 04:23 likes
            drwxr-xr-x 2 1000 1000 4096 Apr 15 04:23 pie
          

For Loops - wildcards


            $ for i in *; do mv $i $i.bak; done
            $ ls -l
            drwxr-xr-x 2 1000 1000 4096 Apr 15 04:23 gavin.bak
            drwxr-xr-x 2 1000 1000 4096 Apr 15 04:23 likes.bak
            drwxr-xr-x 2 1000 1000 4096 Apr 15 04:23 pie.bak
          

For Loops - subshells


            $ for i in $(seq 1 10); do echo $i; done
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
          

Search and Replace

Sed, perl, python, etc

I prefer perl pie


            $ echo "Gavin likes pie" > file.txt
            $ cat file.txt
            Gavin likes pie
            $ perl -pi -e 's/Gavin/Bibi/' file.txt
            $ cat file.txt
            Bibi likes pie
          

Real world example


            for i in $(git ls-files -m); do
            jsonlint $i && git add $i;
            done
          

Real World Example - Find and Replace multiple files


            grep -r onedr0p . | \
            awk -F: '{print $1}' | \
            xargs perl -pi -e 's#ghcr.io/onedr0p#ghcr.io/home-operations#g'
          

Non standard tools - JQ

https://jqlang.org/


            $ curl -qs 'https://jsonplaceholder.typicode.com/todos/1' | jq '.'
            {
            "userId": 1,
            "id": 1,
            "title": "delectus aut autem",
            "completed": false
            }
            $ curl -qs 'https://jsonplaceholder.typicode.com/todos/1' | jq '.id'
            1
            $ curl -qs 'https://jsonplaceholder.typicode.com/todos/1' | jq '.completed'
            false
          

Non standard tools - gron

https://github.com/tomnomnom/gron


            $ curl -qs 'https://jsonplaceholder.typicode.com/todos/1' | gron
            json = {};
            json.completed = false;
            json.id = 1;
            json.title = "delectus aut autem";
            json.userId = 1;
          

Eg curl + jq + gron


            $ curl -qs 'https://jsonplaceholder.typicode.com/todos' | jq '[.[] | select(.completed == true)][0]' | gron
            json = {};
            json.completed = true;
            json.id = 4;
            json.title = "et porro tempora";
            json.userId = 1;
          

The End

colorful painted easter egg

https://m.do.co/c/7d6859326b6a DigitalOcean Referral Badge

Extra Stuffsssss

Slides that were already done but decided against bringing them up

Debugging

Run a script in debug mode

$ bash -x script.sh

Enable debugging right now

$ set -x

SSH

What are ssh keys?

Why would you want them?

How do you use them?

man ssh_config

Whats going on?

  • ps xf -A (My Favourite)
  • ps aux (Very portable)
    • More w's with ps = more wide
    • ps auxwww
  • pstree
  • top

Home Directories


            $ cd
            /home/gavinm
          

            $ cd ~
            /home/gavinm

            $ cd $HOME
            /home/gavinm
Another users home dir

            $ cd ~halkeye
            /home/halkeye

How to get there? - Apple

  • Terminal.app
  • Iterm2