Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
becki:linux:bash [2011-03-30 07:56] becki |
becki:linux:bash [2016-03-03 11:25] (aktuell) becki [File Inclusion, Command Execution] |
||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
- | ====== Bash Programming ====== | + | ====== Bash Programming == |
+ | ===== Documentation == | ||
+ | - [[kman>man1/bash.1|Bash man page]] | ||
+ | - [[http://tldp.org/LDP/abs/html/|Advanced Bash-Scripting Guide]] | ||
===== File Inclusion, Command Execution == | ===== File Inclusion, Command Execution == | ||
Zeile 13: | Zeile 16: | ||
**command** | **command** | ||
- | when the shell encounters a command, it forks off a child process to actually execute the command (external commands only; from abs-guide) FIXME: Is this true? Isn't this ''%%command &%%''? | + | when the shell encounters a command, it forks off a child process to actually execute the command (external commands only; from abs-guide). Parent script blocks until child process ends |
+ | |||
+ | **command &** | ||
+ | |||
+ | forks off a child process to execute the command and put child process into background so that the parent script continues immediately | ||
**eval command ...** | **eval command ...** | ||
Zeile 20: | Zeile 27: | ||
For me useful if command contains spaces witch are protected by single quotes, eg ''%%wget -S --header'Content-Type: application/json'%%''. Without eval, ''%%--header'Content-Type:%%'' and ''%%application/json'%%'' would be interpreted as 2 single arguments | For me useful if command contains spaces witch are protected by single quotes, eg ''%%wget -S --header'Content-Type: application/json'%%''. Without eval, ''%%--header'Content-Type:%%'' and ''%%application/json'%%'' would be interpreted as 2 single arguments | ||
+ | |||
+ | ===== Subshells == | ||
+ | |||
+ | FIXME | ||
+ | |||
+ | ===== Coprocesses == | ||
+ | |||
+ | The following example starts a shell function as a coproc and uses the coproc to manipulate a string: | ||
+ | |||
+ | <code bash> | ||
+ | #!/bin/bash | ||
+ | |||
+ | test_coproc() { | ||
+ | read rein | ||
+ | echo ">$rein<" | ||
+ | } | ||
+ | |||
+ | coproc test_coproc | ||
+ | |||
+ | echo "Hallo" >&${COPROC[1]} | ||
+ | read -u ${COPROC[0]} rein | ||
+ | echo "$rein" | ||
+ | #cat <&${COPROC[0]} # alternative | ||
+ | </code> | ||
+ | |||
+ | ===== Expansion == | ||
+ | |||
+ | FIXME doc ''*'' and ''?'' | ||
+ | |||
+ | <code bash> | ||
+ | echo {a,}quota.{group,user}.new | ||
+ | # prints: aquota.group.new aquota.user.new quota.group.new quota.user.new | ||
+ | # without any regard to the content of the working directory | ||
+ | </code> | ||
+ | |||
+ | ===== Variables == | ||
+ | |||
+ | |||
+ | $meli is a shortcut for ${meli} | ||
+ | |||
+ | ==== Variable Variables == | ||
+ | |||
+ | <code bash> | ||
+ | # get a value from a variable (meli) over a 'pointer' (who): (from abs-guide) | ||
+ | meli=Melanie | ||
+ | who=meli # who is used as pointer to meli | ||
+ | adr=${!who} # now $adr contains Melanie | ||
+ | |||
+ | # set a value into a variable (meli) over a 'pointer' (who): (tried myself) | ||
+ | meli="" | ||
+ | who=meli | ||
+ | eval $(echo $who)=Melanie # now $meli contains Melanie | ||
+ | </code> | ||
+ | |||
+ | ==== Special Variables == | ||
+ | |||
+ | <code bash> | ||
+ | $# # number of command line arguments | ||
+ | $* # Arguments as one word | ||
+ | $@ # Arguments as separate words | ||
+ | $$ # Pid of script | ||
+ | $? # return value of command (& function?) | ||
+ | $! # PID of last job run in background | ||
+ | $0 # full name of script | ||
+ | $1 # first argument of script | ||
+ | </code> | ||
+ | |||
+ | Following a ''shift'' , the ''$@'' holds the remaining command-line parameters, lacking the previous ''$1'', which was lost(([[tldp>LDP/abs/html/othertypesv.html#EX19|Using shift]])). | ||
+ | |||
+ | ==== Default Values == | ||
+ | |||
+ | If variable is not set, expand to default value: | ||
+ | |||
+ | <code bash> | ||
+ | ${variable:-defaultvalue} | ||
+ | |||
+ | # Example: | ||
+ | #Keep Value of VERSION or if not set yet, set it to 3.9: | ||
+ | VERSION=${VERSION:-3.9} | ||
+ | </code> | ||
+ | |||
+ | [[tldp>LDP/abs/html/parameter-substitution.html|Source]] | ||
===== Arrays == | ===== Arrays == | ||
Zeile 32: | Zeile 121: | ||
echo ${app[appix]} # XINE | echo ${app[appix]} # XINE | ||
</code> | </code> | ||
+ | |||
+ | ===== Maps == | ||
+ | |||
+ | See http://stackoverflow.com/questions/1494178/how-to-define-hash-tables-in-bash | ||
===== Loops == | ===== Loops == | ||
Zeile 49: | Zeile 142: | ||
for arg in "$@"; do # $@ sees arguments as separate words. | for arg in "$@"; do # $@ sees arguments as separate words. | ||
echo $arg | echo $arg | ||
+ | done | ||
+ | |||
+ | # Loop through all ogg files of current dir. This is whitepace-save | ||
+ | for fn in *.ogg; do | ||
+ | echo $fn | ||
done | done | ||
Zeile 69: | Zeile 167: | ||
done | done | ||
</code> | </code> | ||
- | |||
- | ===== Variables == | ||
- | |||
- | $meli is a shortcut for ${meli} | ||
- | |||
- | ==== Variable Variables == | ||
- | |||
- | <code bash> | ||
- | # get a value from a variable (meli) over a 'pointer' (who): (from abs-guide) | ||
- | meli=Melanie | ||
- | who=meli # who is used as pointer to meli | ||
- | adr=${!who} # now $adr contains Melanie | ||
- | |||
- | # set a value into a variable (meli) over a 'pointer' (who): (tried myself) | ||
- | meli="" | ||
- | who=meli | ||
- | eval $(echo $who)=Melanie # now $meli contains Melanie | ||
- | </code> | ||
- | |||
- | ==== Special Variables == | ||
- | |||
- | <code bash> | ||
- | $# # number of command line arguments | ||
- | $* # Arguments as one word | ||
- | $@ # Arguments as separate words | ||
- | $$ # Pid of script | ||
- | $? # return value of command (& function?) | ||
- | $0 # full name of script | ||
- | $1 # first argument of script | ||
- | </code> | ||
- | |||
- | Following a ''shift'' , the ''$@'' holds the remaining command-line parameters, lacking the previous ''$1'', which was lost(([[tldp>LDP/abs/html/othertypesv.html#EX19|Using shift]])). | ||
===== Quoting == | ===== Quoting == | ||
Zeile 121: | Zeile 187: | ||
===== Functions == | ===== Functions == | ||
+ | ==== Parameters == | ||
+ | FIXME | ||
<code bash> | <code bash> | ||
- | query() { | + | myfunc() { |
- | echo $*; echo $@; echo $1 | + | echo $* #-> eins zwei drei |
+ | echo $@ #-> eins zwei drei | ||
+ | echo $1 #-> eins | ||
} | } | ||
- | query # call the function | + | myfunc eins zwei drei # call the function |
</code> | </code> | ||
- | Example: | + | ==== Exit Status and return Value == |
+ | |||
+ | The exit status may be explicitly specified by a return statement, otherwise it is the exit status of the last command in the function. Exit status can be checked with ''$?''. | ||
+ | |||
+ | Here is a method to return a string along with the exit status: | ||
<code bash> | <code bash> | ||
- | abort() { | + | myfunc() { |
- | echo "ERROR: $1!" >&2 | + | echo "Hello $1" |
- | if [ "$2" ]; then errcode=$2 ; else errcode=1 ; fi | + | |
- | exit $errcode | + | |
} | } | ||
- | # usage: | + | |
- | [ -d "$SOURCE" ] || abort "Source \"$SOURCE\" is not a directory" | + | res=$(myfunc 'crazy world') # Oddly no quotes necessary in bash and ash |
+ | echo ">>$res<<" | ||
+ | </code> | ||
+ | |||
+ | By using a separator (tab) and the cut command it is possible to return more than one value: | ||
+ | |||
+ | <code bash> | ||
+ | myfunc() { | ||
+ | echo -e "EINS\tZWEI" | ||
+ | } | ||
+ | |||
+ | buf=$(myfunc) | ||
+ | eins=$(echo "$buf" | cut -f1) | ||
+ | zwei=$(echo "$buf" | cut -f2) | ||
+ | |||
+ | echo "$eins - $zwei" #-> EINS - ZWEI | ||
</code> | </code> | ||
Zeile 157: | Zeile 245: | ||
elif [ "$a" == "$b" ] && [ "c" != "d" ]; then # also || | elif [ "$a" == "$b" ] && [ "c" != "d" ]; then # also || | ||
... | ... | ||
- | elif [ ! "$aString" ]; then # true if length==0 or not specified (tested) | + | elif [ -z "$aString" ]; then # true if length==0 |
... | ... | ||
fi | fi | ||
Zeile 170: | Zeile 258: | ||
-h file True if file exists and is a symbolic link. | -h file True if file exists and is a symbolic link. | ||
-r file True if file exists and is readable. | -r file True if file exists and is readable. | ||
- | -s file True if file exists and has a size greater than zero. | + | -w file True if file exists and is writable. |
- | # see also "man bash" -> "Conditional expressions" | + | -s file True if file exists and has a size greater than zero |
+ | -x file has execute permission (for the user running the test) | ||
+ | -z string is null, that is, has zero length | ||
+ | -n string is not null, that is, has not zero length | ||
# Example: | # Example: | ||
- | if [ ! -r "$sorcefile" ]; then | + | if [ ! -r "$sourcefile" ]; then |
echo "Error: Cant read $sorcefile!" | echo "Error: Cant read $sorcefile!" | ||
exit 2 | exit 2 | ||
Zeile 179: | Zeile 271: | ||
</code> | </code> | ||
- | ===== Redirection ===== | + | See also: [[man>test]] and [[man>bash]] -> "Conditional expressions" |
- | <code bash> | + | ===== Exit status of a command == |
- | command > file.txt # stdout 2 file | + | |
- | command 2> file.txt # stderr 2 file | + | |
- | command 1>&2 # stdout 2 stderr | + | |
- | command >&2 # stdout 2 stderr ? | + | |
- | command 2>&1 # stderr 2 stdout | + | |
- | command &> /dev/null # stderr & stdout 2 file (suppress output here) | + | |
- | </code> | + | |
- | + | ||
- | ===== Exit status of a command ===== | + | |
<code bash> | <code bash> | ||
Zeile 202: | Zeile 285: | ||
echo "command was successful" | echo "command was successful" | ||
fi | fi | ||
+ | </code> | ||
+ | |||
+ | ''abort'', my useful helper function: | ||
+ | <code bash> | ||
+ | abort () { | ||
+ | if [ -n "$1" ]; then echo "$(basename $0): $1" >&2; fi | ||
+ | if [ -n "$2" ]; then err="$2"; else err=1; fi | ||
+ | exit $err | ||
+ | } | ||
+ | |||
+ | # usage examples: | ||
+ | [ -d "$SOURCE" ] || abort "Source \"$SOURCE\" is not a directory" | ||
+ | |||
+ | a_command || abort "Command failed" 7 | ||
+ | |||
+ | a_long_command | ||
+ | [ $? -eq 0 ] || abort "long command failed" | ||
+ | </code> | ||
+ | |||
+ | ===== Redirection == | ||
+ | |||
+ | <code bash> | ||
+ | command > file.txt # stdout 2 file | ||
+ | command 2> file.txt # stderr 2 file | ||
+ | command 1>&2 # stdout 2 stderr | ||
+ | command >&2 # stdout 2 stderr ? | ||
+ | command 2>&1 # stderr 2 stdout | ||
+ | command &> /dev/null # stderr & stdout 2 file (suppress output here) | ||
</code> | </code> | ||