This is a collection of my favorite Tips and Tricks in Linux and on the Shell. I will expand it in the future :)

Use Git to manage your Config Files

If you have config files, that you change from time to time, make a (local-only or also remote) Git Repository out of it! This brings a couple of handy features and benefits such like:

  • Change History: As you can use Git to view the changes of each commit you can easily do rollbacks and you know what your colleagues did before they went on vacation.
  • Backup Solution: If you also push your changes to a Git server you can also have a simple backup solution for them.
  • Git as a Rescue System: Breaking changes and accidentally deleted or overwritten files are no longer a problem for you, just revert the happy little accident.
  • Quick Checkouts: As you can do checkouts and diffs between every commit you can also compare more complicated situations without having to struggle with juggling between multiple copies.

Fast Copy

You may have noticed that copying a very large or a lot of files can be quite slow with cp. As a workaround you can compress them with tar, before you pipe them to another tar in a different directory:

tar cf - . | (cd /your/destination; tar xvf -)

You can add pv to the command to get a more verbose output:

tar cf - . | pv | (cd /dst; tar xf -)

Try and Catch

Also known as for example try / except in Python.

You will probably be familiar with the logical operators on the Shell to control the flow of a set of commands by each previous return value (such as AND && and OR ||):

command1 && \
run_this_when_command1_succeeded || \
run_this_when_command1_failed

This type of code can become hard to follow when getting more complex with multiple ANDs and ORs. To avoid this problem, you can also use a workaround using braces { ... } to group commands:

{ # try
    command1
} || { # catch
    run_this_when_command1_failed 
}

A longer example:

{ # try 
    command1 && 
    run_this_when_command1_succeeded &&
    echo This worked! &&
    exit 0
} || { # first catch 
    { # another try inside first catch
        run_this_when_command1_failed && 
        echo First command failed but second succeeded! &&
        exit 1
    } || { # second catch 
        run_this_when_first_catch_failed &&
        exit 2
    }
}

Modern Data Stream Redirection and Piping

Redirecting and Piping the output of data streams like stderr to stdout is one of the most used features in Linux.

Redirection

With Bash Version 4 a new abbreviation for 2>&1 was introduced: >& Example:

root@local:~$ rm missing-file
rm: cannot remove 'missing-file': No such file or directory
root@local:~$ rm missing-file >& command_output.txt
root@local:~$ cat command_output.txt
rm: cannot remove 'missing-file': No such file or directory
root@local:~$

Piping

Instead of command 2>&1 | tee -a logfile.log you can also use command |& tee -a logfile.log to pipe both data streams.

Bash Variable with default Value

This is something I saw on Stackexchange and found very useful as it helps to write clean code.

You can assign a default value to a variable if the value of another, passed variable is either empty or undefinied.

NOTE: This “other variable” can be the same or another variable.

excerpt

${parameter:-word}
    If parameter is unset or null, the expansion of word is substituted. 
    Otherwise, the value of parameter is substituted.

NOTE: This form also works, ${parameter-word}. If you’d like to see a full list of all forms of parameter expansion available within Bash then I highly suggest you take a look at this topic in the Bash Hacker’s wiki titled: “Parameter expansion”.

Examples

variable doesn’t exist

$ echo "$VAR1"

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
default value

variable exists

$ VAR1="has value"
$ echo "$VAR1"
has value

$ VAR1="${VAR1:-default value}"
$ echo "$VAR1"
has value

More Examples

$ echo "${VAR1-0}"
has another value
$ echo "${VAR2-0}"
has another value
$ echo "${VAR3-0}"
0
$ VARX="${VAR3-0}"
$ echo "$VARX"
0

In the above $VAR1 & $VAR2 were already defined with the string “has another value” but $VAR3 was undefined, so the default value was used instead, 0.

Evaluating a variable with another

The same thing can be done by evaluating other variables, or running commands within the default value portion of the notation.

$ VAR2="has another value"
$ echo "$VAR2"
has another value
$ echo "$VAR1"

$

$ VAR1="${VAR1:-$VAR2}"
$ echo "$VAR1"
has another value

Checking and assigning using := notation

Lastly I’ll mention the handy operator, :=. This will do a check and assign a value if the variable under test is empty or undefined.

Example

Notice that $VAR1 is now set. The operator := did the test and the assignment in a single operation.

$ unset VAR1
$ echo "$VAR1"

$ echo "${VAR1:=default}"
default
$ echo "$VAR1"
default

However if the value is set prior, then it’s left alone.

$ VAR1="some value"
$ echo "${VAR1:=default}"
some value
$ echo "$VAR1"
some value

Reference Table

Set and Not NullSet But NullUnset
${parameter:-word}substitute parametersubstitute wordsubstitute word
${parameter-word}substitute parametersubstitute nullsubstitute word
${parameter:=word}substitute parameterassign wordassign word
${parameter=word}substitute parametersubstitute nullassign word
${parameter:?word}substitute parametererror, exiterror, exit
${parameter?word}substitute parametersubstitute nullerror, exit
${parameter:+word}substitute wordsubstitute nullsubstitute null
${parameter+word}substitute wordsubstitute wordsubstitute null

References