Lukáš Bařinka
man bash
stdin connected (typically from terminal - readline)stdin (obykle terminál - readline)man bash
/^INVOCATION
Script is executed as a non-interactive non-login shell
Skript je spouštěn jako neinteraktivní/nonlogin shell, který
~/.bashrc file unless variable BASH_ENV is setexpand_aliases is set.bashrc pokud není nastavená proměnná BASH_ENVexpand_aliasesThat's why a shell environment is more predictable in scripts!
Díky tomu je lépe predikovatelné prostředí běhu skriptu!
It's not typically necessary nor desirable!
Toto obvykle není potřeba ani žádoucí!
echo "alias gg='ping google.com'" > /tmp/rc
export BASH_ENV=/tmp/rc
cat <<END >/tmp/google
#!/bin/bash
shopt -s expand_aliases
gg
END
chmod +x /tmp/google
/tmp/google
man bash
/^ALIASES
Bourne shell cannot evaluate AE, LE nor RE, it uses external commands for that purpose:
Bourne shell neuměl vyhodnocovat AE, LE ani RE, na tuto práci používal externí příkazy:
expr
for arithmetic expressions
pro aritmetické výrazy
test
for logical expressions
pro logické výrazy
grep
for regular expressions
pro regulární výrazy
Bash can evaluate AE, LE and RE inside special built-in environments/commands for expressions
Bash již má podporu pro AE, LE i RE zabudovanou jako prostředí (příkazy)
(( AE/LE ))
for arithmetic expressions
pro aritmetické výrazy
[[ LE/RE ]]
for logical and regular expressions
pro logické a regulární výrazy
(( expression )) or let expression
(( výraz )) nebo let expression
00, is considered as an octal number0x, is considered as a hexadecimal numberbase#, default is decimal00, je chápáno jako oktalové0x, je chápáno jako hexadecimálníbase#, výchozí je decimální
var=09; echo $((var))
bash: 09: value too great for base (error token is "09")
var=0xa; echo $((var))
10
var=09; echo $((10#$var))
9
a=ff; echo $((16#a)) $((16#$a))
10 255
var=09; echo $((var))
bash: 09: hodnota je pro základ příliš velká (chybný token je „09“)
var=0xa; echo $((var))
10
var=09; echo $((10#$var))
9
a=ff; echo $((16#a)) $((16#$a))
10 255
man bash
/^ARITHMETIC EVALUATION
[[ expression ]]
[[ výraz ]]
[[, [ and test are built-in in bash&&, ||, ! instead of -a (and), -o (or), \! (not)<, >, (, ) instead of \<, \>, \(, \)== operator [[ $var == a* ]]=~ operator [[ $var =~ ^[0-9]+$ ]]test, resp. [ vestavěný i [[-a (and) a -o (or) a \! lze psát &&, || a !\< a \>, \( a \) lze psát < a >, ( a )== může být shell vzor (pattern) [[ $var == a* ]]=~ je regulární výraz (ERE) [[ $var =~ ^[0-9]+$ ]][[ value =~ RE ]]
[[ hodnota =~ RE ]]
( and )
BASH_REMATCH array[0] = everything matching RE[1]..[n] = parts matching subexpressions( a )
BASH_REMATCH[0] = vše co odpovídá celému RE[1]..[n] = řetězce odpovídající podvýrazůmman bash
/^CONDITIONAL EXPRESSIONS
shopt -s extglob
[[ or case
?(list) zero or one@(list) one*(list) zero or more+(list) one or more!(list) complement (negation)|[[ nebo case
?(list) nula nebo jeden výskyt@(list) jeden výskyt*(list) nula a více výskytů+(list) jeden a více výskytů!(list) doplněkshopt -s nocasematch nocaseglob
Script is a sequence of commands written into a file
Skript je posloupnost příkazů zapsaných do souboru
#!/bin/bash or #!/bin/awk -f
It is interpreted by the same shell as current shell otherwise
bash my_script.sh or awk -f my_script.awk
e.g.: chmod +x my_script.sh; ./my_script.sh
What has to be done to run the script directly writting my_script.sh? Is there only one way?
exit [n], unless it gets a signal. An exit code of the script depends on the last command or on received signal.#!/bin/bash nebo #!/bin/awk -f
jinak se interpretuje stejným shellem jako je aktuální
bash my_script.sh nebo awk -f my_script.awk
např: chmod +x my_script.sh; ./my_script.sh
Co je potřeba udělat, aby bylo možné skript spouštět přímo pomocí my_script.sh, existuje více možností?
exit [n], návratový kód určuje poslední vykonaný příkaz (nebo signál)$0 command/script name$1, $2, … parameters their meaning is specified by a programmer$# number of parameters$* "$*" ~ "$1 $2 $3 …"all parameters as single string $@ "$@" ~ "$1" "$2" "$3" …each parameter as individual string$0 název programu$1, $2, … parametry význam určuje programátor$# počet parametrů$* "$*" ~ "$1 $2 $3 …"všechny parametry jako jeden řetězec$@ "$@" ~ "$1" "$2" "$3" …každý parametr jako samostatný řetězec
./my_script.sh -v -o out.ps -b in1.pdf in2.pdf
$0 $1 $2 $3 $4 $5 $6 $#=6
while getopts vo:b opt; do
case "$opt" in
v) VERBOSE=1;;
o) OUTPUT="$OPTARG";;
b) BORDER=1;;
\?) echo "$USAGE" >&2; exit 2;;
esac
done
shift `expr $OPTIND - 1`
./my_script.sh in1.pdf in2.pdf
$0 $1 $2 $#=2
while [ $# -gt 0 ]; do
process "$1"
shift
done
for arg in "$@"; do
process "$arg"
done
[ "$DEBUG" -eq 1 ] && echo "Debug: X[$X]" >&2
set -v or set -o verboseset +v or set +o verboseset -x or set -o xtraceset +x or set +o xtrace[ "$DEBUG" -eq 1 ] && echo "Debug: X[$X]" >&2
set -v nebo set -o verboseset +v nebo set +o verboseset -x nebo set -o xtraceset +x nebo set +o xtrace
# non-critical part
set -x
# critical part
set +x
# non-critical part
#!/bin/bash -v
set commands into code. It is possible to run the interpreter with -v or -x options.
bash -vx /usr/bin/ssh-copy-id fray1.fit.cvut.cz
# nekritická část
set -x
# kritická část
set +x
# nekritická část
#!/bin/bash -v
set je možné spustit interpretr s přepínači -v nebo -x.
bash -vx /usr/bin/ssh-copy-id fray1.fit.cvut.cz
Unnamed function
Nepojmenovaná funkce
{ command; command; ...; command; }(command; command; ...; command){ command; command; ...; command; }(command; command; ...; command)
[ -r data ] && {
echo "$HEAD"
cat data
echo "$TAIL"
} > data.new
(
IFS=$'\n' ; cd "$BASE"
tar cf - $SOURCES
) | ssh host ...
$1, $2, …, $#, $@, $*$0 remains unchanged (script name), function name in $FUNCNAMEreturn [n]export -f functionunset -f functiondeclare -F, or declare -f$1, $2, …, $#, $@, $*$0 se nemění (název skriptu), jméno funkce je ve $FUNCNAMEreturn [n]export -f funkceunset -f funkcedeclare -F, resp. declare -f
my_fce () { block of commands; } # sh, ksh, bash
function my_fce { block of commands; } # ksh, bash
function my_fce () { block of commands; } # bash
my_fce
my_fce arg1 arg2 arg3 …
my_fce () { blok příkazů; } # sh, ksh, bash
function my_fce { blok příkazů; } # ksh, bash
function my_fce () { blok příkazů; } # bash
my_fce
my_fce arg1 arg2 arg3 …
man bash
/^FUNCTIONS
source or . commandsource nebo .
BC=/etc/bash_completion
[ -f "$BC" ] && . "$BC"
type command prints out a way of interpretation of its parameter
alias, keyword, function, builtin, file
Příkaz type vypíše způsob interpretace řetězce
alias, klíčové slovo, funkce, součást shellu, soubor
type ll
ll is aliased to `ls -l'
type function
function is a shell keyword
type quote
quote is a function
quote () { printf "'%s'" "${1//\'/\'\\\'\'}"; }
type cd
cd is a shell builtin
type awk
awk is /usr/bin/awk
type ll
ll je alias na „ls -l“
type function
function je klíčové slovo shellu
type quote
quote je funkce
quote () { echo \'${1//\'/\'\\\'\'}\'; }
type cd
cd je součást shellu
type awk
awk je /usr/bin/awk
Some of external commands are built-in
Některé externí příkazy jsou vestavěné
loop1() { loop2() {
local i=0 local i=0
while [ $i -lt 1000 ]; do while [ $i -lt 1000 ]; do
echo $i echo $i
((i++)) i=`expr $i + 1`
done done
} }
time loop1
user: 0.140s | system: 0.008s | real: 0.151s
enable -n echo; time loop1
user: 2.756s | system: 2.344s | real: 3.529s
enable -n echo [ ; time loop1
user: 5.404s | system: 2.344s | real: 6.640s
enable -n echo [ ; time loop2
user: 7.568s | system: 4.596s | real: 10.678s
loop1() { i=0; while [ $i -lt 1000 ]; do echo $i; ((i++)); done; }
loop2() { i=0; while [ $i -lt 1000 ]; do echo $i; i=`expr $i + 1`; done; }
| # | echo | test | i++ | T:user | T:system | T:real |
|---|---|---|---|---|---|---|
| 1. | ✔ | ✔ | ✔ | 0.140s | 0.008s | 0.151s |
| 2. | ✘ | ✔ | ✔ | 2.756s | 2.344s | 3.529s |
| 3. | ✘ | ✘ | ✔ | 5.404s | 4.596s | 6.640s |
| 4. | ✘ | ✘ | ✘ | 7.568s | 7.208s | 10.678s |
declare varlocal var-g option inside function are globaldeclare -g vardeclare varlocal var-g přepínačem uvnitř funkce jsou globálnídeclare -g var
Variables don't have a type by default
Proměnné jsou v základu netypové
X=5; Y=text
echo "$X"; echo "${Y}s"
declare or typeset command
declare -i vardeclare -l vardeclare -u vardeclare -a vardeclare -A vardeclare -n ref=vardeclare -r vardeclare nebo typeset
declare -i vardeclare -l vardeclare -u vardeclare -a vardeclare -A vardeclare -n ref=vardeclare -r varhelp declare
declare -a arrayarray=(val1 [3]=val3 val4 … )array[5]=val5array+=( val6 )"${array[3]}""${array[@]}""${#array[@]}""${!array[@]}"declare -a arrayarray=(val1 [3]=val3 val4 … )array[5]=val5array+=( val6 )"${array[3]}""${array[@]}""${#array[@]}""${!array[@]}"
typeset -A students
eval students=(`ypcat passwd \
| cut -d: -f1,5 \
| sed -n 's/^/[/;s/:/]="/
s/ student$/"/p'
`)
for username in "${!students[@]}"; do
echo "$username ⇒ ${students[$username]}"
done
${parameter:-word}${parameter:=word}${parameter:?word}${parameter:+word}${parameter:offset}${parameter:offset:length}${#parameter}${parameter#word}${parameter##word}${parameter%word}${parameter%%word}${parameter/pattern/string}${parameter/#pattern/string}${parameter/%pattern/string}${parameter//pattern/string}${parameter^pattern${parameter^^pattern}${parameter,pattern}${parameter,,pattern}/var/cache/edux/rz
NULLGLOB=`shopt -p nullglob`
shopt -s nullglob
for i in !(`date +%Y-%m`*)/ ; do
i=${i%/}
p=${PWD//\//_}
p=${p#_}
tar cvzf "${p}_$i.tgz" "$i" && rm -rf "$i"
done
$NULLGLOB
...
2021-12-30/
2021-12-31/
2022-01-01/
...
2022-01-29/
2022-01-30/
2022-01-31/
2022-02-01/
2022-02-02/
...
function node {
local item
((depth++))
pushd "$1" >/dev/null 2>/dev/null || { ((depth--)); return; }
parent[depth]=$1
for item in *; do
(IFS=/; printf -- "%s/%s\n" "${parent[*]}" "$item")
[ -d "$item" ] && node "$item"
done
unset 'parent[depth]'
popd >/dev/null
((depth--))
}
depth=0
declare -a parent
shopt -s nullglob
echo "$1"
node "$1"
./top-down.sh /tmp
DEBUG signal
trap 'read
clear
echo "DEPTH=$depth
PARENT=\"${parent[*]}\"
ITEM=$item"' DEBUG
set -T
DEBUG
trap 'read
clear
echo "DEPTH=$depth
PARENT=\"${parent[*]}\"
ITEM=$item"' DEBUG
set -T
read (build-in)REPLY-a array-d delim-e -N num -s -t time -u fd stdin)read (vestavěný)REPLY-a array-d delim-e -N num -s -t time -u fd stdin)
read a b c a b c
☞1 2☜ '1' '2' ''
read item junk item junk
☞42 foo bar☜ '42' 'foo bar'
read line line
☞ my long line ☜ 'my long line'
read REPLY
☞ my long line ☜ ' my long line '
cat file | while read item junk ; do
((item > max)) && max=$item
done
echo "$max"
while read i ; do
((item > max)) && max=$i
done < file
echo "$max"
(( 10#$item > 10#$max ))
select compound command loopCan be nested
select item in val1 val2 val3 ... EXIT ; do
[ "$item" = EXIT ] && break
echo "$item"
done
^DbreakPS3 variable
PS3='Choose a value: '
select cyklusLze vnořovat
select item in val1 val2 val3 ... KONEC ; do
[ "$item" = KONEC ] && break
echo "$item"
done
^DbreakPS3
PS3='Zvolte hodnotu: '
[ -f "$F" ] || echo "$0: '$F' is not a file" >&2
cat >/etc/resolv.conf <<FIN
domain techlib.cz
search techlib.cz
nameserver 10.0.12.55
nameserver 10.0.12.13
FIN
tr '[[:lower:]]' '[[:upper:]]' <<<"$PATH"
[ -f "$F" ] || echo "$0: '$F' is not a file" >&2
cat >/etc/resolv.conf <<KONEC
domain techlib.cz
search techlib.cz
nameserver 10.0.12.55
nameserver 10.0.12.13
KONEC
tr '[[:lower:]]' '[[:upper:]]' <<<"$PATH"
echo text1 text2 text3 ...
echo -e "Text1\tText2\nText3"
Text1 Text2 ?or? -e Text1\tText2\nText3
Text3
echo > file
echo "$var"
printf format text1 text2 text3 ...
printf "%s\n" "Text1\tText2\nText3"
printf "%s\t%s\n%s\n" "Text1" "Text2" "Text3"
printf "%d:%s\n" 1 a 2 b 3 c 4 d 5 e
printf '%s' "" > file
printf '%s\n' "$var"
Try to avoid usage of temporary files,
that can prevent a lot of problems:
Snažte se vyhnout dočasným souborům, odpadají tak všechny další problémy:
mktemp commandPříkaz mktemp$0.$$ as a temporary filename is predictable!
[ -O "/tmp/$0.$$" ] || echo error
mktemp command
TEMP=$( mktemp ) || echo error
mktemp -d
$0.$$ jako název souboru je předvídatelný!
[ -O "/tmp/$0.$$" ] || echo error
mktemp
TEMP=$( mktemp ) || echo error
mktemp -d
mktemp detailsPodrobnosti k mktemptmp.XXXXXX as an argument
mktemp my_file.XXX
at least 3 characters long suffix
/tmp by default can be specified using -p option
mktemp -p "$HOME"
or using TMPDIR env. variable
export TMPDIR=/var/tmp
mktemp
tmp.XXXXXX Lze změnit argumentem
mktemp soubor.XXX
s délkou přípony min 3 znaky
/tmp Lze ovlivnit přepínačem -p
mktemp -p "$HOME"
nebo proměnnou prostředí TMPDIR
export TMPDIR=/var/tmp
mktemp
man bashhelp builtin_command