Filters
Zo zoek je
  • Gewone woorden vinden namen, teksten en voorbeelden.
  • "twee woorden" vindt precies die zin.
  • --naam of -x vindt een optie.
  • #woord zoekt alleen in commando's.
  • @grep vindt lessen en labs die grep gebruiken.
  • Filters: cat:network · in:labs · in:notes · level:rhcsa · ch:8 · root:yes. Zet ! voor een woord om het weg te laten. OR tussen woorden betekent één ervan.
  • ↑ ↓ bewegen · Enter openen · Esc sluiten · / zoeken

Hoofdstuk 1Naam in de cursus: Shell Scripting and the Command Line

Write shell scripts and work faster on the command line

A task you do twice should become a script. A Bash script is a text file with commands, plus variables, tests and loops that make it smart. This chapter shows how to write and run a script, how to use input and exit codes, and how to use loops and tests both in scripts and directly at the prompt.

  • 8 Lessen
  • 19 Commando's
  • 1 Labs

Dit deel is nog niet vertaald. Je ziet de Engelse tekst.

$ als gewone gebruiker# als root (of met sudo)

Vaardigheden in dit hoofdstuk

  • Bash-scripts schrijven met variabelen, tests en lussen

1.1

Write and run your first script

A script is a text file. The first line (#!/bin/bash, the shebang) says which program runs it. Make it executable and start it with its path.

~/bin/sysinfo.sh
#!/bin/bash
# Show a short report about this machine
echo "Host:   $(hostname)"
echo "Kernel: $(uname -r)"
echo "Uptime: $(uptime -p)"
df -h /
mkdir -p ~/bin
vim ~/bin/sysinfo.sh
chmod +x ~/bin/sysinfo.sh
~/bin/sysinfo.sh
sysinfo.sh
bash ~/bin/sysinfo.sh
  • ~/bin is in the PATH of normal users on RHEL, so sysinfo.sh works from any folder. For all users, put scripts in /usr/local/bin.
  • bash FILE runs a script without the execute right — handy to test.

Onthoud

Comments start with #. Write one line at the top about what the script does — you will thank yourself in a year.

1.2

Use variables and quotes

NAME=value sets a variable (no spaces around =). $NAME or ${NAME} reads it. Put variables in double quotes so spaces do not break them.

BACKUP_DIR=/srv/backup
echo "Backups go to $BACKUP_DIR"
FILE="my report.txt"
touch "$FILE"
echo "${BACKUP_DIR}/etc-$(date +%F).tar.gz"
/srv/backup/etc-2026-10-27.tar.gz
COUNT=$(ls /etc | wc -l)
echo "There are $COUNT entries in /etc"
echo $(( 7 * 6 ))
42
(( COUNT > 100 )) && echo "many"
FormMeaning
VAR=valueSet a variable for this shell
export VARAlso give it to programs started from this shell
$(command)The output of a command
$(( 2 + 3 ))Calculate with whole numbers
${VAR:-default}The value, or default when VAR is empty
${VAR:?message}Stop the script with a message when VAR is empty

Let op

FILE=my report.txt (no quotes) tries to run the command report.txt. And rm $FILE without quotes deletes two files: my and report.txt.

1.3

Read the input of a script

The words after the script name are its positional parameters: $1, $2 … $# is their number, "$@" is all of them.

~/bin/mkusers.sh
#!/bin/bash
# Create one user for every name given on the command line
if [ $# -eq 0 ]; then
    echo "Usage: $0 NAME [NAME ...]" >&2
    exit 1
fi
for name in "$@"; do
    useradd "$name" && echo "created $name"
done
mkusers.sh mia leo sara
created mia
created leo
created sara
read -p "Which host? " HOST
echo "You typed $HOST"
VariableMeaning
$0The name of the script
$1 … $9Parameter 1 … 9 (${10} for more)
$#The number of parameters
"$@"All parameters, each one kept as its own word
$?The exit status of the last command
$$The PID of the script

1.4

Use exit codes

Every command returns a number: 0 = success, 1–255 = a problem. Your script should do the same with exit N, so other tools (cron, systemd, Ansible) know if it worked.

grep -q root /etc/passwd
echo $?
0
grep -q nosuchuser /etc/passwd
echo $?
1
ping -c1 -W1 server2 &> /dev/null && echo up || echo down
/usr/local/bin/checkdisk.sh
#!/bin/bash
# Exit 2 when the root file system is more than 90 % full
USED=$(df --output=pcent / | tail -1 | tr -dc '0-9')
if [ "$USED" -gt 90 ]; then
    echo "CRITICAL: / is ${USED}% full"
    exit 2
fi
echo "OK: / is ${USED}% full"
exit 0

1.5

Test conditions

[ … ] (the test command) and [[ … ]] (Bash) check files, text and numbers. They return 0 (true) or 1 (false).

TestTrue when
-e FILE / -f FILE / -d DIRIt exists / is a normal file / is a folder
-r / -w / -x FILEYou may read / write / run it
-s FILEIt exists and is not empty
-z "$S" / -n "$S"The text is empty / not empty
"$A" = "$B" / !=Texts are equal / different
N -eq M, -ne, -lt, -le, -gt, -geNumber compare: =, ≠, <, ≤, >, ≥
[[ $S == web* ]]Pattern match (only in [[ ]])
[[ $S =~ ^[0-9]+$ ]]Regular expression match (only in [[ ]])
!, &&, ||Not, and, or
[ -f /etc/hosts ] && echo "file exists"
[ -d /srv/backup ] || mkdir -p /srv/backup
test "$USER" = root && echo "you are root"
[[ $(hostname) == server* ]] && echo "a lab server"

Onthoud

Spaces are needed inside the brackets: [ -f FILE ], not [-f FILE].

1.6

Choose with if and case

if runs a block only when a test is true; elif and else cover the other cases. case compares one value with many patterns.

/usr/local/bin/svc.sh
#!/bin/bash
# Start, stop or show a service: svc.sh start|stop|status NAME
ACTION=$1
SERVICE=${2:?give a service name}
 
case "$ACTION" in
    start|stop|restart)
        systemctl "$ACTION" "$SERVICE" ;;
    status)
        if systemctl is-active --quiet "$SERVICE"; then
            echo "$SERVICE is running"
        elif systemctl is-failed --quiet "$SERVICE"; then
            echo "$SERVICE FAILED"
            exit 2
        else
            echo "$SERVICE is stopped"
        fi ;;
    *)
        echo "Usage: $0 start|stop|restart|status SERVICE" >&2
        exit 1 ;;
esac

Notitie

if tests the exit code of any command — not only [ ]. if grep -q …, if ping -c1 …, if systemctl is-active --quiet … are all fine.

Commando's in deze les

1.7

Repeat with for and while

for runs a block once for every item in a list. while runs it as long as a test is true — often to read a file line by line.

for h in server1 server2 server3; do ping -c1 -W1 $h &> /dev/null && echo "$h up" || echo "$h DOWN"; done
for f in /var/log/*.log; do echo "$f: $(wc -l < "$f") lines"; done
for i in {1..5}; do echo "test $i"; done
for u in $(cut -d: -f1 /etc/passwd); do echo "$u"; done | head -3
while read -r host; do ssh "$host" uptime; done < hosts.txt
n=0; while [ $n -lt 3 ]; do echo "n=$n"; n=$((n+1)); done
/usr/local/bin/waitfor.sh
#!/bin/bash
# Wait until a host answers ping (max. 60 tries), then go on
HOST=${1:?host name}
for try in $(seq 1 60); do
    if ping -c1 -W1 "$HOST" &> /dev/null; then
        echo "$HOST is up after $try tries"
        exit 0
    fi
    sleep 1
done
echo "$HOST did not answer" >&2
exit 1

Op het werk

Loops are not only for scripts. One for line at the prompt can check 20 servers in a few seconds.

1.8

Find bugs in a script

bash -x prints every line before it runs, with the values filled in. set -euo pipefail stops the script at the first error.

bash -x ~/bin/sysinfo.sh
+ hostname
+ echo 'Host:   server1.example.com'
Host:   server1.example.com
bash -n ~/bin/mkusers.sh
Safe start for any script
#!/bin/bash
set -euo pipefail
SettingEffect
bash -n FILECheck the syntax only, run nothing
bash -x FILE / set -xTrace: show each command before it runs
set -eStop when a command fails
set -uStop when an unset variable is used
set -o pipefailA pipe fails when any part fails

More: the RHCSA chapter about scripts.

Oefenen

Alle commando's in dit hoofdstuk