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