Bash goodies

CONGRATULATIONS (insert a huge and very irritating blinking banner here)
You are customer number $(zgrep /var/log/apache2/access.log*|wc -l)

Today I'll share some funny and usefull bash goodies with you.
Well actually to tell you the truth I really just want to document this for my future self, because my past self knew this once but now my current self seems to have forgotten and is currently relearning it again (again again).

I'll do this in a Q/A fasion, and btw. please feel free to comment if you think I'm missing something or you have a smarter way of doing stuff or if what I'm saying is actually just completely wrong.

:-)


Q: How do I give variables a default value?

A: you can use the operator :-

TMPDIR=${1:-/var/tmp}


Q: How can I stop the script if a variable is not set?

A: well the classical way to do this is by checking it with "if" sentences, but a simpler way to do the same looks like this:

TMPDIR=${1:?}

when running this it will look like this:

$ ./test.sh
./test.sh: line 3: 1: parameter null or not set

but the users of this script might not really know what is wrong so we can also set a message
TMPDIR=${1:?"Please remember to specify a temporary directory"}

$ ./test.sh
./test.sh: line 3: 1: Please remember to specify a temporary directory

Q: How can I get the length of variable?

A: add the "#" sign before the variable name

TMPDIR${#1}

$ ./test.sh /var/tmp/
9

Q: How can I remove trailing slashes from path?

A: we can use the string manipulation operator "%"

SOURCE_DIR=${1%/}

this will remove a trailing "/" for the variable, this is actually quite usefull if you are building a rsync script and you want to make sure that you are either copying a directory or only its content

$ ./test.sh /var/tmp/
/var/tmp

Q: How can I remove leading slashes from path?

A: same as above but just use the string manipulation operator "#" instead of "%"


Q: how can I get only the filename in a path?

A: either use basename or string manipulation operators ##/*/

#!/bin/bash
VAR1=`basename ${1}`
VAR2=${2##/*/}
echo $VAR1
echo $VAR2

running this will look like this:

./test.sh /var/log/error.log /var/log/access.log
error.log
access.log

However the problem with using basename is if you don't feed it, it will fail

./test.sh
usage: basename string [suffix]
	basename [-a] [-s suffix] string [...]

What's the difference between #/*/ and ##/*/ you ask?
well #/*/ would only remove first occurence (from the left) so if used in this example it would only remove /var/ from the path leaving behind log/apache2/access.log


Q: how can I get only the path in a filepath

A: either use dirname or string manipulation operators %/*

#!/bin/bash
VAR1=`dirname ${1}`
VAR2=${2%/*}
echo $VAR1
echo $VAR2

running this will look like this:

$ ./test.sh /var/log/error.log /var/log/access.log
/var/log
/var/log

you will have the same problem as with basename when using dirname when it doesn't get an argument it will fail.

$ ./test.sh
usage: dirname path

Q: How can I replace strings in a variable?

A: you can do simple stuff with the / operator or you can use sed

VAR=${1/World/Humans!}

$ ./test.sh "Hello World"
Hello Humans!

Note: this will only replace the first occurance or "World"
if you want to replace all occurances you should two slashes like this:
VAR=${1//World/Humans!}

but if you need to do more advanced stuff you should really look into sed


Q: How can I convert variable to (lower|UPPER)case?

A: In Bash 4.x you can use these operators

#!/bin/bash
echo "${1,,}"
echo "${1^^}"

running this will look like this:

$ ./test.sh "Hello World"
hello world
HELLO WORLD

If your bash is older that 4.x it will look like this:

$ ./test.sh "Hello World"
./test.sh: line 2: ${1,,}: bad substitution
./test.sh: line 3: ${1^^}: bad substitution

I will add more Q/A's when and if I suddently remember something old or learn something new.
I hope its usefull to others as it is to me