Bash scripting


Her er nogle eksempler på hvordan man bruger bash mange stærke sider. Liste er meget lang og har taget mig en del tid at lave.

Bash scripting oversigt

#!/usr/bin/env bash
NAME="John"
echo "Hello $NAME!"

Variabler

NAME="John"
echo $NAME
echo "$NAME"
echo "${NAME}!"

Strenge i bash

NAME="John"
echo "Hej $NAME"  #=> Hej John
echo 'Hej $NAME'  #=> Hej $NAME

Shell udførelse af kommando

echo "I'm in $(pwd)"
echo "I'm in `pwd`"
# Her betyder $(kommando) og `kommando` det samme.

Betinget udførelse

git commit && git push
git commit || echo "Commit failed"

Funktioner

get_name() {
  echo "John"
}
echo "You are $(get_name)"

Betingelser

if [[ -z "$string" ]]; then
  echo "String is empty"
elif [[ -n "$string" ]]; then
  echo "String is not empty"
fi

Brace ekspansion

echo {A,B}.js
{A,B} Samme som A B
{A,B}.js Samme som A.js B.js
{1..5} Samme som 1 2 3 4 5

Parametre expansions

Basics

name="John"
echo ${name}
echo ${name/J/j}    #=> "john" (Erstat tegn)
echo ${name:0:2}    #=> "Jo" (Udskriver 2 tegn fra position 0)
echo ${name::2}     #=> "hn" (Udskriver de første 2 tegn)
echo ${name::-1}    #=> "Joh"
echo ${name:(-1)}   #=> "n" (fra højre)
echo ${name:(-2):1} #=> "h" 
echo ${food:-Cake}  #=> "Cake"
length=2
echo ${name:0:length}  #=> "Jo"

Se: Parameter expansion

STR="/path/to/foo.cpp"
echo ${STR%.cpp}    # /path/to/foo
echo ${STR%.cpp}.o  # /path/to/foo.o
echo ${STR##*.}     # cpp (extension)
echo ${STR##*/}     # foo.cpp (basepath)
echo ${STR#*/}      # path/to/foo.cpp
echo ${STR##*/}     # foo.cpp
echo ${STR/foo/bar} # /path/to/bar.cpp
STR="Hello world"
echo ${STR:6:5}   # "world"
echo ${STR:-5:5}  # "world"
SRC="/path/to/foo.cpp"
BASE=${SRC##*/}   #=> "foo.cpp" (basepath)
DIR=${SRC%$BASE}  #=> "/path/to/" (dirpath)

Substitution

${FOO%suffix} Fjern suffix
${FOO#prefix} Fjern prefix
${FOO%%suffix} Fjern langt suffix
${FOO##prefix} Fjern langt prefix
${FOO/from/to} Erstat første match
${FOO//from/to} Erstat alt
${FOO/%from/to} Erstat suffix
${FOO/#from/to} Erstat prefix

Kommentarer

# Enkelt linje kommentar
: '
Flere linje
kommentar
'

Substrings

${FOO:0:3} Substring (position, længde)
${FOO:-3:3} Substring fra højre

Længde

${#FOO} Længte af $FOO

Default værdi

${FOO:-val} $FOO, or val Hvis ikke sat
${FOO:=val} Set $FOO to val Hvis ikke sat
${FOO:+val} val if $FOO Hvis sat
${FOO:?message} Vis fejl medelse og exit hvis $FOO ikke er sat

Tegnet  : er valgfri (Eks, ${FOO=word} virker også)

Løkker

Basis for løkker

for i in /etc/rc.*; do
  echo $i
done

Områder

for i in {1..5}; do
    echo "Welcome $i"
done

Løkker med step størrelser

for i in {5..50..5}; do
    echo "Welcome $i"
done

Læs linjer

< file.txt | while read line; do
  echo $line
done

For evigt

while true; do
  ···
done

Funktioner

Definere en funktion.

myfunc() {
    echo "hello $1"
}
# Samme som ovenfor (med alternativ syntax)
function myfunc() {
    echo "hello $1"
}
myfunc 
"John"

Retur værdier

myfunc() {
    local myresult='some value'
    echo $myresult
}

Her bliver result lig med resultatet som returneres fra kaldet af myfunc.

result="$(myfunc)"

Returnere fejl.

myfunc() {
  return 1
}
if myfunc; then
  echo "success"
else
  echo "failure"
fi

Argumenter

$# Number af argumenter
$* Alle argumenter
$@ Alle argumenter, start fra start
$1 Første argument

See Special parameters.

Betingede

Noter dig venlist af  [[ faktisk et program som returnere enten  0 (true) eller 1 (false) set fra shell fejl kode. Alle programmer har samme logik  (så som alle base kommandoer, som eks. grep(1) eller ping(1)) kan blive brugt, se eksempler.

[[ -z STRING ]] Tom streng
[[ -n STRING ]] Ikke tom streng
[[ STRING == STRING ]] Ligmed
[[ STRING != STRING ]] Ikke ligmed
[[ NUM -eq NUM ]] Ligmed
[[ NUM -ne NUM ]] Ikke ligmed
[[ NUM -lt NUM ]] Mindre
[[ NUM -le NUM ]] Mindre eller samme
[[ NUM -gt NUM ]] Støre en
[[ NUM -ge NUM ]] Støre eller samme
[[ STRING =~ STRING ]] Regexp
(( NUM < NUM )) Numerisk test
[[ -o noclobber ]] If OPTIONNAME er aktiv
[[ ! EXPR ]] Not
[[ X ]] && [[ Y ]] And
[[ X ]] || [[ Y ]] Or

Fil betingelser

[[ -e FILE ]] Findes
[[ -r FILE ]] Kan læses
[[ -h FILE ]] Symlink fil
[[ -d FILE ]] Bibliotek på disk
[[ -w FILE ]] Skrivebar
[[ -s FILE ]] Størrelse er > 0 bytes
[[ -f FILE ]] En Fil
[[ -x FILE ]] Kan startes
[[ FILE1 -nt FILE2 ]] 1 er nyere en fil 2
[[ FILE1 -ot FILE2 ]] 2 er nyere en fil  1
[[ FILE1 -ef FILE2 ]] Samme filer

Eksempler

if ping -c 1 google.com; then
  echo "Din internet virker ping google ok."
fi
if grep -q 'foo' ~/.bash_history; then
  echo "Du har skrevet 'foo' tidligere"
fi
# String
if [[ -z "$string" ]]; then
  echo "Streng er tom"
elif [[ -n "$string" ]]; then
  echo "Streng er ikke tom"
fi
# Combinations
if [[ X ]] && [[ Y ]]; then
  ...
fi
# Equal
if [[ "$A" == "$B" ]]
# Regex
if [[ "A" =~ "." ]]
if (( $a < $b )); then
   echo "$a er mindre en $b"
fi
if [[ -e "file.txt" ]]; then
  echo "fil findes"
fi

Arrays

Definere arrays

Fruits=('Apple' 'Banana' 'Orange')
Fruits[0]="Apple"
Fruits[1]="Banana"
Fruits[2]="Orange"

Arbejde med arrays

echo ${Fruits[0]}           # Element #0
echo ${Fruits[@]}           # Alle elementer, space-separated
echo ${#Fruits[@]}          # Antal af elementer
echo ${#Fruits}             # Længe på tekst på første element
echo ${#Fruits[2]}          # Længe på tekst på N element 
echo ${Fruits[@]:1:2}       # (fra position 1, elementer 2)

Operations

Fruits=("${Fruits[@]}" "Watermelon")    # Push
Fruits+=('Watermelon')                  # Igen Push
Fruits=( ${Fruits[@]/Ap*/} )            # Fjern med regex mash
unset Fruits[2]                         # Fjern et element
Fruits=("${Fruits[@]}")                 # Duplikere
lines=(`cat "logfile"`)                 # Læs fra program output

Iteration

for i in "${arrayName[@]}"; do
  echo $i
done

Kommander

history Viser historien over de sidst kommandoer udført
shopt -s histverify Udfør ikke udvidet resultat straks

Expansions

!$ Expand last parameter of most recent command
!* Expand all parameters of most recent command
!-n Expand nth most recent command
!n Expand nth command in history
! Expand most recent invocation of command

Operations

!! Viser kommandoen og udføre sidste kommando igen.
!!:s/// Replace first occurrence of to in most recent command
!!:gs/// Replace all occurrences of to in most recent command
!$:t Expand only basename from last parameter of most recent command
!$:h Expand only directory from last parameter of most recent command

!! and !$ can be replaced with any valid expansion.

Slices

!!:n Expand only nth token from most recent command (command is 0; first argument is 1)
!^ Expand first argument from most recent command
!$ Expand last token from most recent command
!!:n-m Expand range of tokens from most recent command
!!:n-$ Expand nth token to last from most recent command

!! can be replaced with any valid expansion i.e. !cat, !-2, !42, etc.

Andre diverse muligheder.

Numeriske beregninger

$((a + 200))      # Addere 200 til $a
$((RANDOM%=200))  # Random nummer mellem 0..200

Shell i shells

Her udføres et cd til dirsted men står stadig i det bibliotek som du startede med at stå i.

(cd dirsted; echo "Vi er nu i $PWD biblioteket")
pwd # still in first directory

Omdirigering af output.

python hello.py > output.txt   # stdout til (file)
python hello.py >> output.txt  # stdout til (file), tilføj til filen.
python hello.py 2> error.log   # stderr til (file)
python hello.py 2>&1           # stderr til stdout
python hello.py 2>/dev/null    # stderr til (null)
python hello.py &>/dev/null    # stdout og stderr til (null)
python hello.py < foo.txt      # feed foo.txt til stdin for python

Inspektion af kommandoer.

command -V cd
#=> "cd is a function/alias/whatever"

Fang fejl.

trap 'echo Error at about $LINENO' ERR

eller

traperr() {
  echo "ERROR: ${BASH_SOURCE[1]} at about ${BASH_LINENO[0]}"
}
set -o errtrace
trap traperr ERR

Case/switch

case "$1" in
  start | up)
    vagrant up
    ;;
  *)
    echo "Usage: $0 {start|stop|ssh}"
    ;;
esac

Kilde relativ

source "${0%/*}/../share/foo.sh"

printf

printf "Hello %s," Jeg er Olga
#=> "Hello Sven, Jeg er Olga

Directory i script

DIR="${0%/*}"

Getting options

while [[ "$1" =~ ^- && ! "$1" == "--" ]]; do case $1 in
  -V | --version )
    echo $version
    exit
    ;;
  -s | --string )
    shift; string=$1
    ;;
  -f | --flag )
    flag=1
    ;;
esac; shift; done
if [[ "$1" == '--' ]]; then shift; fi

Heredoc

cat <

Reading input

echo -n "Proceed? [y/n]: "
read ans
echo $ans
read -n 1 ans    # Just one character

Special variables

$? Exit status fra sidste task
$! PID fra sidste backgrounds task
$ PID nr på shell

Se også Special parameters.

Gå til sidste bibliotek

pwd # /home/user/foo
cd bar/
pwd # /home/user/foo/bar
cd -
pwd # /home/user/foo

Her er flere links til guider om bash. Men de er på engelsk.

Loading