Bash
Online GNU Docs https://www.gnu.org/software/bash/manual/html_node/index.html#SEC_Contents
Redirections
Online GNU Docs: Redirections: https://www.gnu.org/software/bash/manual/html_node/Redirections.html
each process starts with three streams:
stdin, fd=0
stdout, fd=1
stderr, fd=2
# redirect std err, to prevent it from printing on the console or other files
sudo apt update 2>/dev/null
# redirect stdout and std err to separate files
ls -la 1>ls_stdout 2>ls_stderr
# invalid option to demonstrate the error stream
ls -! 1>ls_stdout 2>ls_stderr
# redirect stdout to a file, and stderr to stdout
ls -la &> ls_out
# which is equivalent to
ls -la 1>ls_out 2>&1
# append-redirect stdout to a file, and stderr to stdout
ls -la &>> ls_out
# Redirect stdout to stdout (FD 1)
echo "hello there" 1>&1
# Redirect stdout to stderr (FD 2)
echo "hello there" 1>&2
# Redirect stderr to stdout
echo "hello there" 2>&1
Bash Pipelines
# cmd1 | cmd2
groups | sed 's/\s\+/,/g'
the
|to pipe stdout to stdin of next cmdthe
|&to redirect stderr to stdout before piping to stdinthe
|&is equivalent to tocmd1 2&>1 | cmd2
- Another idea is to use
xargs build and execute command lines from standard input
# generate a sequence of 5 numbers, and build arguments for the echo command
seq 0 5 | xargs echo
# generate a compact listing of all users on the System
cut -d: -f1 < /etc/passwd | sort | xargs echo
# pipline over SSH for a series of hosts
for k in thinkpad uraspi znode;
do ssh $k "mkdir /bits/zkeys && mv /bits/vpnkeys /bits/zkeys/pki"; done
Bash Command Lists
# execute A, then execute B if A was successful
echo A && echo B
# execute B only if A fails
echo A || echo B
# execute A, then Execute B
echo A; echo B
# execute A, B and C in parallel
echo A & echo B & echo C &
Bash special parameters (Special Variables)
- GNU Man Pages: Special Parameters
https://www.gnu.org/software/bash/manual/bash.html#Special-Parameters
$$ own process ID
echo $$
MYPID=$$
echo $MYPID
$! the pid of the last background-ed process
# run in the background
tail -f /var/log/dmesg &
bgtail_pid=$! # better store the PID before it flies
echo $bgtail_pid
# and then later use it, probably by sending a signal
kill -s SIGQUIT $bgtail_pid
$# the count of positional args starting of a function from 1
a_test_func () {
echo $#
}
a_test_func hello world "a quoted hello world, making a total of 3 args"
$* and $@ expansion of positional arguments, starting from 1
There are subtle differences between the two:
"$*"is equivalent to"$1 $2 ...""$@"is equivalent to"$1" "$2" ...
a_test_func () {
echo got $# args: "$*"
echo alt syntax: "$@"
}
a_test_func hello world "a quoted hello world, making a total of 3 args"
$? the exit status of the most recent foreground pipeline
last_status=$? # better store it right away
echo $last_status # then do something with it
$- Bash flags
echo $- # expands to the current bash flags by the set built in command
$1 Position Parameters
echo $0 # expands to the name of the shell, or the shell script invoked
echo $1 # the first positional argument
echo $2 # the second positional argument
Bash Builtins
The declare built-int
declare --help
declare -F # print declared bash function names
declare -f # print declared bash function names and definitions
The set build-in, and Bash flags
set --help
echo $- # expands to the current bash flags by the set built in command
set -e # exit upon non-zero exit code
echo $- # the e flag should now be visible among the default flags
set +e # undo the e flag
generate error on expanding unbound variables
set -u
Bash Loops and Foreach
# explicit positional parameters
for k in bananas apples oranges; do echo $k; done
# expanding a list of tokens
xlang="C Python Bash Javascript"
for k in $xlang; do echo "I love $k"; done
# expanding a function that products a lis of tokens
for k in $(echo C Python Bash Javascript); do echo "I love $k"; done
# looping over arrays
xt=( a b c d )
for item in ${xt[@]}; do echo $item; done
path_tokens=( $( echo "$PATH" | tr ":" " " ) )
for item in ${path_tokens[@]}; do echo $item; done
Bash Tokenization and Splitting
The Internal Field Separator Variable $IFS can be used to determine the splitting character
DEFAULT_IFS=$IFS
langs="python;javascript;ruby"
IFS=";"; for k in $langs; do echo "$k"; done
# Then change it to split the $PATH string
IFS=":"; for p in $PATH; do echo "$p"; done
IFS=$DEFAULT_IFS
# or simply, to go back to the shell default
unset IFS
Another way is to use tr ":" "\n" to replace characters in a string or a stream
langs="python;javascript;ruby"
for k in $(echo $langs | tr ";" " "); do echo "$k"; done
# Then change it to split the $PATH string
for p in $(echo $PATH | tr ":" " "); do echo "$p"; done