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_ENV
expand_aliases
That'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
0
0
, is considered as an octal number0x
, is considered as a hexadecimal numberbase#
, default is decimal0
0
, 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 verbose
set +v
or set +o verbose
set -x
or set -o xtrace
set +x
or set +o xtrace
[ "$DEBUG" -eq 1 ] && echo "Debug: X[$X]" >&2
set -v
nebo set -o verbose
set +v
nebo set +o verbose
set -x
nebo set -o xtrace
set +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 $FUNCNAME
return [n]
export -f function
unset -f function
declare -F
, or declare -f
$1
, $2
, …, $#
, $@
, $*
$0
se nemění (název skriptu), jméno funkce je ve $FUNCNAME
return [n]
export -f funkce
unset -f funkce
declare -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 |
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 var
declare -l var
declare -u var
declare -a var
declare -A var
declare -r var
declare
nebo typeset
declare -i var
declare -l var
declare -u var
declare -a var
declare -A var
declare -r var
help declare
declare -a array
array=(val1 [3]=val3 val4 … )
array[5]=val5
array+=( val6 )
"${array[3]}"
"${array[@]}"
"${#array[@]}"
"${!array[@]}"
declare -a array
array=(val1 [3]=val3 val4 … )
array[5]=val5
array+=( 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
^D
break
PS3
variable
PS3='Choose a value: '
select
cyklusLze vnořovat
select item in val1 val2 val3 ... KONEC ; do [ "$item" = KONEC ] && break echo "$item" done
^D
break
PS3
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 mktemp
tmp.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 bash
help builtin_command