bash
GNU Bourne-Again SHell

Lukáš Bařinka

man bash

TOC

Obsah

  1. Shell Startup and Configuration
  2. Special Environments for Expressions
  3. Shell Script
  4. Function
  5. Execution
  6. Variables
  7. Interactive Scripts
  8. Notes
  1. Spouštění a konfigurace shellu
  2. Rozšířené prostředí
  3. Skript
  4. Funkce
  5. Vykonávání
  6. Proměnné
  7. Interaktivní skripty
  8. Poznámky

Shell Startup and ConfigurationSpouštění a konfigurace shellu

bash rolesbash role

  • login shell started after a login
  • non-login shell started by a terminal program
  • interactive with stdin connected (typically from terminal - readline)
  • non-interactive e.g. script
  • login shell po přihlášení
  • non-login shell po spuštění terminálu
  • interaktivní má připojen stdin (obykle terminál - readline)
  • neinteraktivní skript

man bash
/^INVOCATION

Profile filesProfile soubory

Profile files workflow

Properties and Settings InheritanceNe/dědění vlastností a nastavení

Properties and Settings Inheritance example

Aliasing in Scripts,
Why It Does Not Work
Proč nefungují aliasy ve skriptu?

Script is executed as a non-interactive non-login shell

Skript je spouštěn jako neinteraktivní/nonlogin shell, který

  • It does not execute ~/.bashrc file unless variable BASH_ENV is set
  • It does not expand aliases unless shell option expand_aliases is set
  • Neprovádí .bashrc pokud není nastavená proměnná BASH_ENV
  • Neexpanduje aliasy pokud není nastavena vlastnost 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!

How To Make Aliases Work in ScriptsJak zajistit fungování aliasů ve 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

Special Environments for ExpressionsRozšířená prostředí

sh ᰽ bash

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

sh ᰽ bash

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

Arithmetic ExpressionsAritmetický výraz

(( expression )) or let expression

(( výraz )) nebo let expression

  • Integers only
  • No underflow/overflow check
  • Text is considered as a variable name
  • Non-initialised variable is 0
  • Number beginnig with 0, is considered as an octal number
  • Number beginnig with 0x, is considered as a hexadecimal number
  • Base of number can be chosen using base#, default is decimal
  • Celočíselná aritmetika
  • Bez kontroly na přetečení
  • Text je chápán jako jméno proměnné
  • Neinicializovaná proměnná má hodnotu 0
  • Pokud číslo začíná 0, je chápáno jako oktalové
  • Pokud číslo začíná 0x, je chápáno jako hexadecimální
  • Soustavu čísla lze volit pomocí base#, výchozí je decimální

Arithmetic Expressions - ExamplesAritmetický výraz - příklad


							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

Logical Expression
(Extended test)
Logický výraz
(rozšířený test)

[[ expression ]]

[[ výraz ]]

  • [[, [ and test are built-in in bash
  • &&, ||, ! instead of -a (and), -o (or), \! (not)
  • <, >, (, ) instead of \<, \>, \(, \)
  • Shell pattern on the right side of == operator [[ $var == a* ]]
  • Extended regular expression on the right side of =~ operator [[ $var =~ ^[0-9]+$ ]]
  • V bashi je stejně jako test, resp. [ vestavěný i [[
  • Místo -a (and) a -o (or) a \! lze psát &&, || a !
  • Místo \< a \>, \( a \) lze psát < a >, ( a )
  • Na pravé straně výrazu při textovém porovnání == může být shell vzor (pattern) [[ $var == a* ]]
  • Na pravé straně výrazu při operátoru =~ je regulární výraz (ERE) [[ $var =~ ^[0-9]+$ ]]

Regular ExpressionsRegulární výrazy

[[ value =~ RE ]]

[[ hodnota =~ RE ]]

  • Exit code: 0 value matches RE, 1 values doesn't match RE
  • RE is a word, no globbing perfomed optimally: RE in variable
  • When RE is quoted, then considered as string
  • Subexpressions using ( and )
    • parts of value thaht match RE are stored in BASH_REMATCH array
    • subexpressions can be nested
    • [0] = everything matching RE
    • [1]..[n] = parts matching subexpressions
  • Návratový kód: 0 odpovídá RE, 1 neodpovídá RE
  • RE je slovo, neprovádí se na něm globbing ideálně je RE v proměnné
  • Pokud je RE v apostrofech/uvozovkách, je chápán jako řetězec
  • Možnost použití podvýrazů pomocí ( a )
    • Jednotlivé části odpovídající podvýrazům jsou v poli BASH_REMATCH
    • Je možné podvýrazy i vnořovat do sebe
    • [0] = vše co odpovídá celému RE
    • [1]..[n] = řetězce odpovídající podvýrazům

man bash
/^CONDITIONAL EXPRESSIONS

Extended patterns (extglob)Rozšířené vzory (extglob)

shopt -s extglob

  • Handy for filename generating (globbing)
  • Patternd matching in [[ or case
    • ?(list) zero or one
    • @(list) one
    • *(list) zero or more
    • +(list) one or more
    • !(list) complement (negation)
  • List contains items separated by |
  • Pro generování jmen souborů (globbing)
  • Pro porovnání s hodnotou (matching) v [[ 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ěk
  • Seznam (list) obsahuje položky oddělené |

shopt -s nocasematch nocaseglob

Shell ScriptSkript

Script basicsZáklady psaní skriptů

Script is a sequence of commands written into a file

Skript je posloupnost příkazů zapsaných do souboru

  • The first line could specify an interpreter e.g.: #!/bin/bash or #!/bin/awk -f It is interpreted by the same shell as current shell otherwise
  • Script can be executed using interpreter or directly by itself e.g.: 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?
  • The script ends with the last command or calling built-in command exit [n], unless it gets a signal. An exit code of the script depends on the last command or on received signal.
  • První řádka by měla určovat interpretr např: #!/bin/bash nebo #!/bin/awk -f jinak se interpretuje stejným shellem jako je aktuální
  • Spuštění skriptu pomocí interpretru nebo přímo např: 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í?
  • Skript končí (pokud neobdrží signál) buď posledním příkazem nebo příkazem exit [n], návratový kód určuje poslední vykonaný příkaz (nebo signál)

Script - (Positional) ParametersSkript - (poziční) parametry

  • From user's point of view: command_name [options…] [arguments…]
  • Form program's point of view: command_name [parameters…]
    • $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
  • Z pohledu uživatele: název_programu [přepínače…] [argumenty…]
  • Z pohledu programu: název_programu [parametry…]
    • $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

Options ProcessingZpracování přepínačů


							./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`
						

Arguments ProcessingZpracování argumentů


							./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
						

Script debuggingLadění skriptu

  • Debug messages [ "$DEBUG" -eq 1 ] && echo "Debug: X[$X]" >&2
  • Verbose mode
    • Enabled using set -v or set -o verbose
    • Disabled using set +v or set +o verbose
    • It prints executed code (as written in a script) Before an interpretation
  • XTrace mode
    • Enabled using set -x or set -o xtrace
    • Disabled using set +x or set +o xtrace
    • It prints interpreted code as it looks Before an execution
  • Ladící výpisy [ "$DEBUG" -eq 1 ] && echo "Debug: X[$X]" >&2
  • Verbose režim
    • Zapnutí pomocí set -v nebo set -o verbose
    • Vypnutí pomocí set +v nebo set +o verbose
    • Vypisuje prováděný kód (tak jak je zapsaný ve skriptu) Před interpretací
  • XTrace režim
    • Zapnutí pomocí set -x nebo set -o xtrace
    • Vypnutí pomocí set +x nebo set +o xtrace
    • Vypisuje interpretovaný kód, jak vypadá Před spuštěním

Debugging sectionLadění části skriptu

  • Debugging critical part using encapsulation:
    
    									# non-critical part
    									set -x
    									# critical part
    									set +x
    									# non-critical part
    								
  • Debugging whole script using interpreter options:
    
    									#!/bin/bash -v
    								
  • If the script is not writtable, it's impossible to insert 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
  • Ladění kritické části skriptu vložením:
    
    									# nekritická část
    									set -x
    									# kritická část
    									set +x
    									# nekritická část
    								
  • Pro ladění celého skriptu v deklaraci interpretru:
    
    									#!/bin/bash -v
    								
  • Pokud skript není zapisovatelný, není možné do skriptu vložit příkaz 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

FunctionsFunkce

Block of CommandsBlok příkazů

Unnamed function

Nepojmenovaná funkce

  • Running in current shell { command; command; ...; command; }
  • Running in subshell (command; command; ...; command)
  • Běžící v aktuálním shellu { command; command; ...; command; }
  • Běžící v subshellu (command; command; ...; command)

{ list; }{ seznam; }

  • Executed in current shell
  • Can be executed in background/foreground
  • I/O can be redirected for whole list
  • Initialized/changed variables inside block remain after the list
  • Běží v aktuálním shellu
  • Může běžet na popředí/pozadí
  • V/V lze přesměrovat pro celý blok
  • Nastavení z bloku (např. proměnné) existují i po jeho ukončení

							[ -r data ] && {
							  echo "$HEAD"
							  cat data
							  echo "$TAIL"
							} > data.new
						

(list;)(seznam;)

  • Executed in sub-shell
  • Can be executed in background/foreground
  • I/O can be redirected for whole block of commands
  • Initialized/changed variables or settings inside block will not remain after the list e.g. umask, working directory
  • Běží v sub-shellu
  • Může běžet na popředí/pozadí
  • V/V lze přesměrovat pro celý blok
  • Nastavení z bloku již neexistují po jeho ukončení např. proměnné, aktuální adresář, maska

							(
							  IFS=$'\n' ; cd "$BASE"
							  tar cf - $SOURCES
							) | ssh host ...
						

FunctionsFunkce

  • Function is named block of commands
  • Function is executed in current shell Script is executed in subshell
  • Function parameters are stored in $1, $2, …, $#, $@, $*$0 remains unchanged (script name), function name in $FUNCNAME
  • Function ends with last command or return [n]
  • Function is not inherited in child functions can be forced by: export -f function
  • Function can be removed using: unset -f function
  • List of declared functions: declare -F, or declare -f
  • Funkce je pojmenovaný blok příkazů
  • Funkce se vykonává v aktuálním shellu Skript běží v subshellu
  • Parametry funkce jsou dostupné přes $1, $2, …, $#, $@, $*$0 se nemění (název skriptu), jméno funkce je ve $FUNCNAME
  • Funkce končí posledním příkazem nebo příkazem return [n]
  • Funkce se nedědí do potomků lze vynutit: export -f funkce
  • Funkci lze zrušit pomocí: unset -f funkce
  • Seznam funkcí: declare -F, resp. declare -f

Declaration/ExecutionDeklarace/volání

  • There are different types of function declaration in different shells:
    
    									my_fce () { block of commands; }          # sh, ksh, bash
    
    									function my_fce { block of commands; }    # ksh, bash
    
    									function my_fce () { block of commands; }  # bash
    								
  • Function is called using function name (and opt. with parameters)
    
    									my_fce
    									my_fce arg1 arg2 arg3 …
    								
  • Pro deklaraci lze v různých shellech použít různé zápisy:
    
    									my_fce () { blok příkazů; }          # sh, ksh, bash
    
    									function my_fce { blok příkazů; }    # ksh, bash
    
    									function my_fce () { blok příkazů; }  # bash
    								
  • Funce se volá jménem (příp. s parametry)
    
    									my_fce
    									my_fce arg1 arg2 arg3 …
    								

man bash
/^FUNCTIONS

Code sourcingNačítání kódu

  • Function declaration (or any other code) could be stored in a file
  • File containig code can be included using source or . command
  • Sourced code is executed in current shell
  • Deklarace funkcí (nebo jakýkoliv jiný kód) může být uložen v souboru
  • Soubor s kódem je možné načíst pomocí příkazů source nebo .
  • Načítaný kód je vykonávaný aktuálním shellem

							BC=/etc/bash_completion
							[ -f "$BC" ] && . "$BC"
						

ExecutionVykonávání

Command typesTypy příkazů

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
						

Builtin/External CommandsVestavěné/externí příkazy

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
						

ResultsVýsledky


							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; }
						
#echotesti++T:userT:systemT:real
1.0.140s0.008s0.151s
2.2.756s2.344s3.529s
3.5.404s4.596s6.640s
4.7.568s7.208s10.678s

VariablesProměnné

Local VariablesLokální proměnné

Scope of variables

Variable typesTypy proměnných

Variables don't have a type by default

Proměnné jsou v základu netypové


							X=5; Y=text
							echo "$X"; echo "${Y}s"
						
  • Type can be specified using declare or typeset command
    • Integer declare -i var
    • Lower/Upper case declare -l vardeclare -u var
    • Array (indexed/associative) declare -a vardeclare -A var
  • Constant (cannot be changed nor unset) declare -r var
  • Typ lze určit pomocí příkazu declare nebo typeset
    • Integer declare -i var
    • Lower/Upper case declare -l vardeclare -u var
    • Array (indexed/associative) declare -a vardeclare -A var
  • Konstanta (nelze změnit ani zrušit) declare -r var

help declare

ArrayPole

  • Array declaration: declare -a array
  • Values assignment:
    • array=(val1 [3]=val3 val4 … )
    • array[5]=val5
    • array+=( val6 )
  • Value of array item: "${array[3]}"
  • All values of array: "${array[@]}"
  • Number of items in array: "${#array[@]}"
  • Array indices: "${!array[@]}"
  • Deklarace pole: declare -a array
  • Přiřazení hodnot do pole:
    • array=(val1 [3]=val3 val4 … )
    • array[5]=val5
    • array+=( val6 )
  • Hodnoty pole: "${array[3]}"
  • Všechny hodnoty: "${array[@]}"
  • Počet prvků pole: "${#array[@]}"
  • Indexy pole: "${!array[@]}"

Associative ArrayAsociativní pole


							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 ExpansionsExpanze proměnných

Use Default Values
${parameter:-word}
Assign Default Values
${parameter:=word}
Display Error if Null or Unset
${parameter:?word}
Use Alternate Value
${parameter:+word}
Substring Expansion
${parameter:offset}
${parameter:offset:length}
Parameter length
${#parameter}
Remove matching prefix pattern
${parameter#word}
${parameter##word}
Remove matching suffix pattern
${parameter%word}
${parameter%%word}
Pattern substitution
${parameter/pattern/string}
${parameter/#pattern/string}
${parameter/%pattern/string}
${parameter//pattern/string}
Case modification
${parameter^pattern
${parameter^^pattern}
${parameter,pattern}
${parameter,,pattern}

ExampleUkázka

/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/
							...
						

Recursive Descent - DeclarationRekurzivní sestup - deklarace


							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--))
							}
						

Recursive Descent - UsageRekurzivní sestup - použití


							depth=0
							declare -a parent
							shopt -s nullglob
							echo "$1"
							node "$1"
						

							./top-down.sh /tmp
						
  • How to prevent infinite loops by symlinks?
  • Can it loops by hardlink?
  • How to speed up the script?
  • Jak zabránit zacyklení skriptu při zacyklení symbolického linku?
  • Může se zacyklit hardlink?
  • Jak zrychlit tento skript?

Recursive Descent - DebugRekurzivní sestup - ladění

  • Set action for DEBUG signal
    
    									trap 'read
    									      clear
    									      echo "DEPTH=$depth
    									      PARENT=\"${parent[*]}\"
    									      ITEM=$item"' DEBUG
    								
  • Set inheritance of that action into functions
    
    									set -T
    								
  • Nastavení akce na signál DEBUG
    
    									trap 'read
    									      clear
    									      echo "DEPTH=$depth
    									      PARENT=\"${parent[*]}\"
    									      ITEM=$item"' DEBUG
    								
  • Nastavení dědění akce do funkcí
    
    									set -T
    								

Interactive scriptsInteraktivní skripty

Read from inputČtení ze vstupu

  • Command read (build-in)
  • Store input line in given variables (parameters) or array
  • Default variable REPLY
  • Options
    -a array
    Read into array
    -d delim
    Read until first char. of separator (default newline)
    -e             
    Use Readline to obtain the line
    -N num     
    Read num at maximum
    -s             
    Do not echo input (silent)
    -t time   
    Time out and return failure after time reached
    -u fd       
    Read from given file-descriptor (default stdin)
  • Příkaz read (vestavěný)
  • Uloží načítané hodnoty z řádky do proměnných (parametry) nebo do pole
  • Výchozí proměnná REPLY
  • Přepínače
    -a array
    Načte hodnoty do pole array
    -d delim
    Čte vstup až po první znak z delim (výchozí: nový řádek)
    -e             
    Použije knihovnu Readline pro vstupní řádku
    -N num     
    Přečte maximálně num znaků
    -s             
    Neopisuje zadávaný vstup (silent)
    -t time   
    Čtení se ukončí po uplynutí time sekund
    -u fd       
    Čte ze zadaného file-descriptoru (výchozí: stdin)

Read from input - exampleČtení ze vstupu - příklad


							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   '
						

Input processingZpracování vstupu


							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 commandPříkaz select

  • select compound command loopCan be nested
    
    									select item in val1 val2 val3 ... EXIT ; do
    									  [ "$item" = EXIT ] && break
    									  echo "$item"
    									done
    								
  • Input termination
    • ^D
    • break
  • Prompt setup using PS3 variable
    
    									PS3='Choose a value: '
    								
  • Řídící konstrukce (složený příkaz) select cyklusLze vnořovat
    
    									select item in val1 val2 val3 ... KONEC ; do
    									  [ "$item" = KONEC ] && break
    									  echo "$item"
    									done
    								
  • Ukončení vstupu
    • ^D
    • break
  • Nastavení promptu pomocí proměnné PS3
    
    									PS3='Zvolte hodnotu: '
    								

NotesPoznámky

RedirectionPřesměrování

  • Error messages should be printed to error output
    
    									[ -f "$F" ] || echo "$0: '$F' is not a file" >&2
    								
  • Here document/word
    
    									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"
    								
  • Chybové zprávy by se měly posílat na chybový výstup
    
    									[ -f "$F" ] || echo "$0: '$F' is not a file" >&2
    								
  • Here document/word
    
    									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 ᰽ printf


							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"
						

http://wiki.bash-hackers.org/commands/builtin/printf

Temporary FilesDočasné soubory

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:

  • Where to create them?
  • How to name them (uniquely)?
  • Do I have permission to do that?
  • Is there a sufficient disk space for them?
  • Is it safe, what permissions should they have?
  • When to delete them?
  • What if the script terminates early?
  • Kde je mám vytvořit?
  • Jak je mám pojmenovat?
  • Mám na to dostatečná práva?
  • Mám na to dostatečný prostor?
  • Je to bezpečné, jaká jim dát práva?
  • Kdy dočasné soubory smazat?
  • Co s nimi, když skript skončí předčasně?

mktemp commandPříkaz mktemp

  • $0.$$ as a temporary filename is predictable!
  • It is necessary to check the ownership of the file
    
    									[ -O "/tmp/$0.$$" ] || echo error
    								
  • It is better to use mktemp command
    
    									TEMP=$( mktemp ) || echo error
    								
  • It is possible to create a directory
    
    									mktemp -d
    								
  • $0.$$ jako název souboru je předvídatelný!
  • Je nutné provést kontrolu vlastnictví soubor
    
    									[ -O "/tmp/$0.$$" ] || echo error
    								
  • Lépe je použít nástroj mktemp
    
    									TEMP=$( mktemp ) || echo error
    								
  • Lze s ním také vytvořit adresář
    
    									mktemp -d
    								

mktemp detailsPodrobnosti k mktemp

  • Filename can be based on template tmp.XXXXXX as an argument
    
    									mktemp my_file.XXX
    								
    at least 3 characters long suffix
  • Base directory is /tmp by default can be specified using -p option
    
    									mktemp -p "$HOME"
    								
    or using TMPDIR env. variable
    
    									export TMPDIR=/var/tmp
    									mktemp
    								
  • Jméno souboru se vytváří podle šablony tmp.XXXXXX Lze změnit argumentem
    
    									mktemp soubor.XXX
    								
    s délkou přípony min 3 znaky
  • Standardně se soubory vytváří v adresáři /tmp Lze ovlivnit přepínačem -p
    
    									mktemp -p "$HOME"
    								
    nebo proměnnou prostředí TMPDIR
    
    									export TMPDIR=/var/tmp
    									mktemp
    								

Algorithmic NoteAlgoritmická poznámka

Simple tests

Links and LiteratureOdkazy a literatura