Joshua's Cheatsheets
Light
help

Bash / Shell - Cheatsheet

Resources

Current directory:

echo $PWD

Including the "Hash-Bang" / "She-Bang"

#!/bin/bash
  • ^ Should go at the top of sh files.

Commenting

# My comment

Logic / flow

Test

Before using advanced branching logic, you should know that the shell has a built-in test check - basically coerces the output of an expression to a boolean that can be used in logic flows. Simply encase the expression/condition in brackets:

[ check-this-condition ]

or double brackets, as the newer version

If / Else

Great guides

Grep

  • In general, if you are a RegEx power user, you will probably find sed much preferable. Or awk.

    • grep can actually be a bit of a pain when trying to do things like use capture groups (1, 2)
  • Cheatsheets:

  • (Common) Flags:

    Flag Description
    -E Extended regex
    -o Only output the matching part of the line
    -p Treat as perl style regular exp
    -i Ignore case
    -e Pass explicit patterns, multiple allowed

sed

  • Cheatsheets

  • Common flags

    Flag Description
    -n Silent, suppress printing of pattern space
    -r
    (or -E on some systems)
    Use extended regexp - I always prefer
  • Syntax

    • print output

      • echo $'hello world\nLine Two\nGoodbye' | sed -E -n '/Line.+/p'

        • Prints "Line Two"
    • substitute

      • echo $'hello world\nLine Two\nGoodbye' | sed -E 's/Line.+/my substitution/'

        • Prints:

          • hello world
            my substitution
            Goodbye
    • Print only a specific capture group

      • This is actually a little complicated. Basically, you have to substitute the entire input with the back-reference of the capture.

        • sed -E -n 's/.*(My_Search).*/\1/p
      • In action:

        • echo $'hello world\nLine Two\nGoodbye' | sed -E -n 's/.*^Line (.+)$.*/\1/p'

          • Prints:

            • "Two"

Piping and redirection

  • Piping VS Redirection

    • Simple answer:

      • Piping: Pass output to another command, program, etc.
      • Redirect: Pass output to file or stream
  • Pipe

    • |
    • echo 'hello world' | grep -o 'hello'

      • Prints hello
  • Redirection

    • >
    • echo "hello" > output.txt

Problems with piping

Piping, in general, is taking the stdout of one process to the stdin of another. If the process you are trying to pipe to is expecting arguments and doesn't care about stdin, or ignores it, piping won't work as you want it to.

The best solution for this is usually to use xargs, which reads stdin and converts the input into arguments which are passed to the command of your choice.

Or, you can use substitution to capture the result of the first part of the pipe and reuse it in the second.

See this S/O answer for details.

??? - 2>&1

You see 2>&1 all over the place in bash scripts, because it is very useful. Essentially, it forces errors (stderr) to be piped to whatever value stdout is set to.

This has a few really handy and common uses:

  1. See both the output and the errors in the console at the same time

    • Often errors are routed to stderr and not shown in the console.
  2. Suppress errors

    • Since this forces errors to stdout, this has the side effect of suppressing them from their normal destination

      • However, they are still going to show up in stdout obviously. If you really want to suppress them entirely, use 2> /dev/null, which essentially sends them to oblivion
  3. Send both output and errors to file

    • If you redirect to a file before using 2>&1, then both outputs gets sent to the file.

      • ls file-does-not-exist.txt > output.txt 2>&1

        • output.txt will now contain "ls: cannot access 'file-does-not-exist.txt': No such file or directory"

On a more technical level, Unix has descriptors that are kind of like IDs. 2 is the descriptor/id for stderr, and 1 is the id for stdout. In the context of redirection, using & + ID (&{descriptorId}) means copy the descriptor given by the ID. This is important for several reasons - one of which is that 2>1 could be interpreted as "send output of 2 to a file named 1", whereas 2>&1 ensures that it is interpreted as "send output of 2 to descriptor with ID=1".

So... kinda...

  • 2>&1

    • can be broken down into:
  • stderr>&stdout

    • ->
  • stderr>value_of_stdout

    • ->
  • stdout = stderr + stdout

Suppress errors

Make sure to see above section about how descriptors work with redirection, but a handy thing to remember is:

# Pretend command 'foobar' is likely to throw errors that we want to completely suppress
foobar 2>/dev/null

This sends error output to /dev/null, which basically discards all input.

Additional reading

Using variables

Simple:

VARIABLE_NAME=VARIABLE_VALUE

Example:

MYPATH="C:\Users\Joshua"
cd $MYPATH
echo "I'm in Joshua's folder!"

How to store the result of a command into a variable:

  • There are two methods:

    • Command/process substitution (easy to understand)

      VARIABLE_NAME=$(command)
      • However, this doesn't always work with complex multi-step operations
    • read command (complicated) - works with redirection / piping

      echo "hello" | read VARIABLE_NAME

Global path

echo $PATH

Triggering / running a SH file

  • Make sure it is "runnable" - that it has the execute permission

    • chmod +x /scriptfolder/scriptfile.sh
  • Then call it:

    • /scriptfolder/scriptfile.sh

If you are having issues running from Windows...

  • MAKE SURE LINE ENDINGS ARE \n and not \r\n

Keeping file open after execution

Add this to very end of file:

exec $SHELL

Strings

Special characters (newline, etc)

You need to prefix with $ before string to use special characters.

Example:

  • echo 'hello\ngoodbye'

    • Prints:

      • "hello\ngoodbye"
  • echo $'hello\ngoodbye'

    • Prints:

      • "hello
        goodbye"

        Joining Strings

        You can simply put strings together in variable assignment, like this:

        FOO="Test"
        BAR=$FOO"ing"
        echo $BAR

        echoes:

        testing

How to generate keys and certs

  • SSH Key: Using ssh-keygen (available on most Unix based OS's, included Android)

    • You can run it with no arguments and it will prompt for file location to save to

      • ssh-keygen
    • Or, pass arguments, like -t for algorithm type, and -f for filename, -c for comment

      • ssh-keygen -t rsa -C "your_email@example.com"

Create new files, or update existing file timestamps

  • Touch without any flags will create a file if it does not exist, and if it does already exist, update timestamp of "last accessed" to now

    • touch "myfolder/myfile.txt"
  • If you want touch to only touch existing and never create new files, use -c

    • touch -c "myfile.txt"
  • Specifically update last accessed stamp of file

    • touch -a "myfolder/myfile.txt"
  • specifically update "Last MODIFIED" stamp of file

    • touch -m "myfolder/myfile.txt"
  • You can also use wildcard matching

    • touch -m *.txt
  • and combine flags

    • touch -m -a *.txt

Deleting

  • Delete everything in a directory you are CURRENTLY in:

    • Best:

      • find -mindepth 1 -delete
    • UNSAFE!!!

      • rm -rf *
    • Better, since it prompts first:

      • rm -ri *
  • Delete everything in a different directory (slightly safer than above)

    • rm -rf path/to/folder
  • Delete based on pattern

    • find . -name '*.js' -delete

ls - show all files, including hidden files and directories (like .git)

ls -a

Show progress bar / auto-update / keep console updated:

Great SO Q&A

Symlinks (symbolic links)

You can use the ln command (ss64) to create symbolic links.

# Works for both files and directories
ln -s {realTargetPath} {symbolicFileName}

# If you need to update an existing symlink, you need to use "force"
ln -sf {realTargetPath} {symbolicFileName}

In general, it is best / easiest to always use absolute paths for the targets.

Evaluating symlinks

You can use ls -la to list all files, including symlinks.

If you just want to see resolved symlinks, you can use grep - ls -la | grep "\->"


Networking

cURL

  • Good cheatsheets

  • Show headers only curl -I http://example.com
  • Search for something

    • You can't just pipe directly to grep or sed, because curl sends progress info stderr, so use --silent flag:

      • curl --silent https://joshuatz.com | sed -E -n 's/.*<title>(.+)<\/title>.*/\1/p'

        • Prints: Joshua Tzucker&#039;s Site

          How do I...

  • Resolve DNS hostname to IP

    • getent hosts HOST_NAME | awk '{ print $1 }'
    • Credit goes to this S/O
Markdown Source Last Updated:
Sun Nov 17 2019 04:19:58 GMT+0000 (Coordinated Universal Time)
Markdown Source Created:
Mon Aug 19 2019 17:06:24 GMT+0000 (Coordinated Universal Time)