-
Notifications
You must be signed in to change notification settings - Fork 0
BashGuide
A more complete and extensive guide is Advanced Bash-Scripting Guide Many examples are based hereof.
- Operator
&-
executes the command in the background in a subshell
# For example: for n in {1..30}; do wget "https://i11www.iti.kit.edu/_media/teaching/winter2012/algo2/vorlesung${n}.pdf" & # do in subshell -----^^^ done -
does not wait for the command to finish, and the return status is 0
-
- Operator
;- Commands separated by a
;are executed sequentially - The shell waits for each command to terminate in turn
- The return status is the exit status of the last command executed
- Commands separated by a
A double-dash defines the end of options:
ls -lh -- -badName/# introduceds a line comment
$var1 vs. ${var1} (dollar sign + curly braces)
Variable substitution (contents of a variable) (e.g. var1=5; echo $var1 # outputs: 5)
Use parameter substitution (${var1}) instead (same effect but resolves some disambiguities e.g. when concatenating variables with strings).
See also Brace/Variable expansion.
: is a null command. It can be interpreted as a synonym for the shell builtin true.
Exit status is true (/0).
$? returns the exit code of the last command.
echo "pid is $$" prints the process ID.
inputFile="./diff.txt"
while read file; do
cp ${file} "./diffedFiles"
done < ${inputFile}Note that we also use our variable to redirect the contents to the loop (works also to store loop outputs in a variable).
Example using an array:
# Declare an array variable
declare -a arr=("element1" "element2" "element3")
for i in "${arr[@]}"; do
echo "$i"
# Or do whatever with individual element of the array
done
# You can access them using echo "${arr[0]}", "${arr[1]}" alsofor i in {000..999}; do
echo ${i}
doneif [[ "$(ls -A ${pathTemp})" ]] # True if length of string is non-zero
then # Or in one line: `if [[ "$(ls -A ${pathTemp})" ]]; then`
echo "Path is not empty"
# ...
else
echo "path is EMPTY"
# ...
elif [[ <cond> ]]
: # Elif branch (optional)
else
: # Else branch (optional)
fiReturn a status of 0 or 1 depending on the evaluation of the conditional expression expression. The spaces are mandatory.
([ ]: test command; Same as Extended test command / [[ ]]. Prefer [[ ]] over [ ] (see also http://mywiki.wooledge.org/BashFAQ/031). This is more safe but does not work in POSIX-only environments.)
Check if folder /tmp is empty:
[[ "$(ls -A /tmp)" ]] && echo "Not Empty" || echo "Empty"read -p "Press \`Y\` or \`y\` to continue: " -n 1 -r
echo # Print newline after command was entered
if [[ "${REPLY}" =~ ^[Yy]$ ]]
then
: # Continue
else
exit 1
fiHEADER= cat <<'EOF'
Some longe multiline string
with indentations.
EOF
# or for commands:
VAR=$(cat <<EOF
blah
EOF
)-
EOFis just an arbitrary delimiter for the start/end of the here document - Quote (like above) your start/end sequence (e.g.
EOF->'EOF') to avoid escaping -
-EOFto lstrip any leading whitespaces
function noParams {
echo "blah"
exit
}
function withParams {
echo $1
}
# Function call
noParams
# Function call **with** one param
withParams 'Hello'
withParams 'World'Bash does not have return statements. Processing values of a function call can be achieved by echoing the "return"-value.
res=$(noParams)
# res = "blah"Traps react on signals (show std signals with kill -l; EXIT = 0).
- Set trap:
trap 'cmdOrFctName' <SIGNAL> - Signals can be ignored:
trap '' SIGINT - Reset trap:
trap SIGINT(no longer execute traps forSIGINT)
Prints and increments counter until Ctrl-C is pressed (kill with: kill -s SIGKILL <PID>).
counter="0"
trap "echo \$((counter++))" SIGINT SIGTERM
echo "PID is $$"
while :
do
sleep 3
done#!/bin/bash
set -e
trap 'trapFctName $? $LINENO' EXIT
trapFctName() {
if [ "$1" != "0" ]; then
# error handling goes here
printf "Error %s occurred in line %s\n" $1 $2
fi
}
`
--------------------------------------------------------------------------------------
# Redirecting
* `>` : output - write (to file (overwrites existing ones)) **redirects only stdout**
* `>>` : append (to file)
* `<` : input - read (from file)
## Example - appending to a file
Appends all `.txt` files in current directory:
```bash
cat *.txt >> ~/anotherDirectoryToAvoidInfiniteAppending/all.txtPIP_STATUS="$(pip3 install --upgrade pip | tee /dev/tty)"
command identifier1>identifier2
^^^ ^ ^^^
redirect id1 to id2
| std level | identifier |
|---|---|
| Stdin | 0 |
| Stdout | 1 |
| Stderr | 2 |
Redirecting stderr to stdout: &>word, >word 2>&1, and >&word are exactly the same.
# Pipe to "null device" (this discards everything it gets)
ls -R * 2> /dev/null
# or redirect output of stdout to a file (no space after the number!!)
find ./ -name "newfile*" 1> log.txt
# stderrr to stdout
programm 2>&1
# stderr and stdout to file
programm &> Datei.txtUse printf in favour of echo (here is why)
# Prints var as a string
printf '%s' "$var"Some exit codes have special meanings. See also /usr/include/sysexits.h. $? is used to find the return value of the last executed command.
| Exit Code Number | Meaning | Example | Comments |
|---|---|---|---|
0 |
Success | --- | --- |
1 |
Catchall for general errors | let "var1 = 1/0" | Miscellaneous errors, such as "divide by zero" and other impermissible operations |
2 |
Misuse of shell builtins (according to Bash documentation) | empty_function() { } | Missing keyword or command, or permission problem (and diff return code on a failed binary file comparison). |
126 |
Command invoked cannot execute | /dev/null | Permission problem or command is not an executable |
127 |
"command not found" | illegal_command | Possible problem with $PATH or a typo |
128 |
Invalid argument to exit | exit 3.14159 | exit takes only integer args in the range 0 - 255 (see first footnote) |
128+n |
Fatal error signal "n" |
kill -9 $PPID of script |
$? returns 137 (128 + 9) |
130 |
Script terminated by Control-C | Ctl-C | Control-C is fatal error signal 2, (130 = 128 + 2, see above) |
255* |
Exit status out of range | exit -1 | exit takes only integer args in the range 0 - 255 |
Piping to another process:
command1 | command2This will send the output of command1 as the input of command2.
Usually, the last item in a pipeline determines the result (return value).
Sends the output of one process as command line arguments to another process
command2 `command1`For example:
cat `find . -name '*.foo' -print`This will send the output of command1 into command2 as command line arguments. Note that file names containing spaces (newlines, etc.) will be broken into separate arguments, though.
mSearch() {
grep -nC "${2}" -i "$1" 'blub.txt'
# ^--------^--------- second and first argument (actually it begins with zero $0 = script name)
}Syntax:
"${<argumentNumb>-${varName}}"
"${<argumentNumb>-<default-value>}"Example:
mSearch() {
numPadLines=7
# "${2-${numPadLines}} ---> Use numPadLines if 2nd argument is unset
tac "notes.md" | grep -nC "${2-${numPadLines}}" -i "$1" --color=auto --group-separator=***********************************************************
}//TODO: For now see: https://www.gnu.org/software/bash/manual/html_node/Pattern-Matching.html#Pattern-Matching
| Synthax | Explanation |
|---|---|
{ ... } |
Brace expansion |
$var or ${var}
|
Variable/parameter expansion |
( ... ) |
Command group |
(( ... )) |
C-style manipulation + arithmetic expansion and evaluation |
Define constants as read-only
readonly TIMEOUT_S=10Braces are reserved words, so they must be separated from the list by blanks or other shell metacharacters.
- Expanding arrays, as in
${array[42]} - Parameter expansion operations, as in
${filename%.*}(remove extension) - Expanding positional parameters beyond
9: "$8 $9 ${10} ${11}" - Ranges:
$ echo {0..20}
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20- Special usage in
find -exec-
{}substitutes the matches found -
-exectakes a program and arguments and runs (-> it does not execute a full bash) - To overcome this:
$ find $felix -name "PQIS*.zip" -exec bash -c 'echo $(dirname {})' \;
-
$var # use the variable
${var} # same as above
${var}bar # expand var, and append "bar" too
$varbar # same as ${varbar}, i.e expand a variable called varbar, if it exists.
OUTPUT="$(ls -1)"
echo "${OUTPUT}" # Quoting (") does matter to preserve multi-line valuesWhen commands are grouped, redirections may be applied to the entire command list.
- Command group ( e.g.
(a=hello; echo $a)) - Array init (e.g.
Array=(element1 element2 element3))
Since if requires a non-empty then clause and comments don't count as non-empty, [: serves as a no-op](#:\ /\ Colon\ /\ non-op\ command).
if command; then :; else ...; ficount_tmp() { cd /tmp; files=(*); echo "${#files[@]}"; }
pwd; count_tmp; pwd # pwd : "print working directory"Output
/home/mrspaceinvader
11
/tmp
Function body executes in a subshell
cd ; unset files
count_tmp() (cd /tmp; files=(*); echo "${#files[@]}")
pwd; count_tmp; pwdOutput
/home/mrspaceinvader
11
/home/mrspaceinvader
Permits arithmetic expansion and evaluation (e.g. a=$(( 5 + 3 )); would set a to 8). Allows C-style manipulation of variables in Bash, for example, (( var++ )) or (( var = 42 )) or ((var+=42)).
Everything is a string (no typing in bash)
$ blah="blub"
$ echo ${#blah}
4Starts the string at position 1 (bash starts counting at 0) until the end (legth of string)
$ echo ${blah:1:${#blah}}
lahOr get rid of the last character
$ echo ${blah::-1}
blaHowever,
$ echo ${blah:1:}prints nothing.
Better quote everything (e.g. rm "$2" << might contain spaces; without quotes you'll get a list of files to delete)
Variable references are instantly expanded.
If you want selective expansion inside a string - i.e., expand some variable references, but not others - do use double quotes, but prefix the $-references which you do not want to expand with \; e.g., \$var).
Strings inside single quotes are not expanded or interpreted in any way by the shell.
See [if fi chapter](#if\ /\ Tests\ /\ Expression\ evaluation\ (if\ and\ fi)) for usage.
-
-eq: is equal to (f.ex.:if [ "$a" -eq "$b" ]) -
-ne: is not equal to -
-gt: is greater than -
-ge: is greater than or equal to -
-lt: is less than -
-le: is less than or equal to -
<: is less than (within double parentheses) (f.e.x.:(("$a" < "$b"))) -
<=: is less than or equal to (within double parentheses) -
>: is greater than (within double parentheses) -
>=: is greater than or equal to (within double parentheses)
-
=/==: is equal to (f.ex.:if [ "$a" = "$b" ]; Note the whitespace framing of=)Note: The
==comparison operator behaves differently within a double-brackets test than within single brackets:
[[ $a == z* ]] # True if $a starts with an "z" (pattern matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).
[ $a == z* ] # File globbing and word splitting take place.
[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).-
!=: is not equal to -
</>: is less/greater than, in ASCII alphabetical order (</>needs to be escaped within a[ ]construct) -
-z: string is null, that is, has zero length -
-n: string is not null
:()
{
:|:&
};
::() #Define new function
#named ':'
{ #Begin function definition
#block
:|:& #Pipe the very ':' function through itself,
#creating two processes, and make the
#resulting copy run in the background
#(the & part)
} #End function definition block
;: #Call ':' for the first time, initiating a chain
#reaction: each instance of ':' will create two
#more instances, ad infinitumset -eset -o xtrace-> Also prints evaluation of
- http://tldp.org/LDP/abs/html/index.html
- http://tldp.org/LDP/GNU-Linux-Tools-Summary/html/GNU-Linux-Tools-Summary.html
- http://tldp.org/guides.html
- http://www.gnu.org/software/bash/manual/bash.html
- http://stackoverflow.com/questions/864316/how-to-pipe-list-of-files-returned-by-find-command-to-cat-to-view-all-the-files
- http://google.github.io/styleguide/shell.xml
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License *.
Code (snippets) are licensed under a MIT License *.
* Unless stated otherwise
