Redirection reminders
# stdout to file
$ foo > file
# stderr to file
$ foo 2> file
# stderr+stdout to stdout (optionally piped through tee)
$ foo 2>&1 | tee all-output.txt
# stderr+stdout to file
$ foo > file 2>&1
# NON-STANDARD shorthand for merging standard error and standard output
$ foo >& file # NOT POSIX
# stdout to file, stderr to different file
$ foo > file 2> errors
# output to stderr
$ echo foo 1>&2
# convenience function to output to stderr:
echoerr() { echo "$@" 1>&2; }
# stderr to stdout, but stdout to /dev/null, and pipe stderr (http://stackoverflow.com/a/2342841)
$ foo 2>&1 >/dev/null | grep 'something'
Default value for a variable
echo "-------------------------------------------------------------------------"
echo "Using ':=', 'one' and 'two' are empty, both end up with the default value"
unset one
unset two
one="${two:=default value}"
echo "one=$one" # one=default value
echo "two=$two" # two=default value
echo "-------------------------------------------------------------------------"
echo "Using ':-', 'one' and 'two' are empty, 'one' ends up with the default value, 'two' remains empty"
unset one
unset two
one="${two:-default value}"
echo "one=$one" # one=default value
echo "two=$two" # two=
echo "-------------------------------------------------------------------------"
echo "Using ':=', 'one' is empty, 'two' has a value, both end up with the value in 'two'"
unset one
two='two'
one="${two:=default value}"
echo "one=$one" # one=two
echo "two=$two" # two=two
echo "-------------------------------------------------------------------------"
echo "Using ':-', 'one' is empty, 'two' has a value, both end up with the value in 'two'"
unset one
two='two'
one="${two:-default value}"
echo "one=$one" # one=two
echo "two=$two" # two=two
The variable doesn’t have to be assigned. Just echoing, or using the :
(which
does nothing, like a comment, but still executes it, unlike a comment) is enough
to be set to the default variable:
echo "Using program from ${program:-$HOME/local/program/bin}"
echo $program # Empty! The above printed the default, but the variable is not set
echo ${variable:=default value} # default value
echo $variable # default value
# This was set up correctly
More reading:
Splitting a string without bash arrays
The original solution comes from Stack Overflow, but I don’t like much the disguised if-else nesting short circuit:
var="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
while [ "$var" ] ;do
iter=${var%%;*}
echo "> [$iter]"
[ "$var" = "$iter" ] && \
var='' || \
var="${var#*;}"
done
Reworking it a bit to my taste:
INPUT="foo bar baz"
while [ "$INPUT" ]; do
item=${INPUT%% *}
echo "working on $item"
if [ "$INPUT" = "$item" ]; then
INPUT='' # done
else
INPUT="${INPUT#* }" # trim variable
fi
done
Quotes, empty spaces, and other junk
Recommended:
if [ "$FOO" = "foo" ] ; then
echo "expected output"
fi
Note
|
|
This is a fail:
FOO='' # empty string [ -f $FOO ] && echo true # Prints true, but there is no file with empty file name...
Caution
|
This is old fashioned, and has security risks: if [ x$VARIABLE = x ] ; then echo "Empty variable \$VARIABLE" fi |
A counter
# TODO: bashism?
counter=$((counter+1))
Recursively list files by time
find -type f -printf '%T+\t%p\n' | sort -n
Create a bunch of files
for i in `seq -w 0 999` ; do dd if=/dev/zero of=./file_$i.zr bs=4096 count=10 ; done