Shellprogrammieren mit Bash
Ulrich Fiedler
Shellprogrammieren mit Bash
Inhaltsverzeichnis
•
•
•
Einführung (15 min)
Shell Typen
Einführung in die Shell-Programmierung
– Variablen / vordefinierte Variablen (15 min)
– Substitution (Shell Preprocessing) (15 min)
– Quoting (Metazeichen) (15 min)
•
Weiterführende Themen der Shell-Programmierung
–
–
–
–
–
–
–
–
•
Test (10 min)
Flusskontrolle (if, case,while, for, select) (10 min)
Umleitung von Ein- und Ausgabe (15 min)
Parameteruebergabe, Optionen abarbeiten (10 min)
Funktionsaufrufe (10 min)
Texte filtern: head, tail, grep, tr, sort, unique (10 min)
Reguläre Ausdrücke (15 min)
sed (10 min)
Zusammenfassung
Shellprogrammieren mit Bash
Am Anfang war die Shell …
Shellprogrammieren mit Bash
Die Shell (Englisch für Schale, Muschel)
• Schnittstelle zum
Betriebssystemkernel, die eine
Eingabe und Interpretation von
ausführbaren Kommandos
ermöglicht.
Die Eingabe erfolgt über
• Kommandozeile (interaktiv)
• Shellskripts (nicht interaktiv)
• Die erlaubte Komplexität der
Eingaben ist vergleichbar ist mit der
einer einfachen Programmiersprache
Shellprogrammieren mit Bash
Interpretation der Kommandozeile
• Ermöglicht eingebaute Kommandos auszuführen
• Z.B. eine Variable setzen in der Bash Shell
– Set DISPLAY 129.132.30.15
• Ermöglicht mit Utility Programmen
(Binaries, compilierte Programme) zu arbeiten
• Z.B. Editor starten:
– emacs
• im Hintergrund starten („Job-Kontrolle“):
– emacs &
• Ein- oder Ausgabe eines Programms umlenken („Redirection“):
– ls > dir.txt
• Ausgabe eines Programm als Eingabe eines anderen Programms
verwenden („pipelining“ – glue things together)
– tail –f logfile | more
Eingabe
Programm 1
Ausgabe
Pipe
Eingabe
Programm 2
Shellprogrammieren mit Bash
Ausgabe
Interpretation von Shellskripts
•
Ermöglicht es sich wiederholende Abläufe zu automatisieren
• Systemstart
• Einloggen - Startskripts der Login-Shell
– Systemgenerisches Skript
» Bsp. Bash-Shell: /etc/profile
– Login Shell Skript
» Bsp.: Bash-Shell: ~/.profile (oder ~/.bash_profile, ~/.bash_login)
• Starten einer neuen Shell – Startskript einer Nichtanmeldeshell (Bash)
» Hier können z.B.der Suchpfad für ausführbare Programme gesetzt werden
» Bsp.: Bash-Shell: ./bashrc
• Schliessen einer Shell – Abmeldeskript
» Bsp. Bash-Shell: ./bash_logout
• Systeme installieren
– Install configure usw.
• Systeme administrieren (z.B. neuen User einführen)
• Zusammenstecken von Anwendungsprogrammen
» Z.B. generieren einer Postskriptsdatei aus LaTex Quellen
Shellprogrammieren mit Bash
Shell Typen
• Unix/Linux bietet verschiedene Shells an:
• Bourne, Bash und Korn Shell
» Algol-ähnliche Syntax, User-Prompt: „$“
• C, TC-Shell (terminal based C-Shell)
» C ähnliche Syntax, User-Prompt: „%“
• Diese Shells können auch remote benützt werden
• rsh (remote shell):
• ssh (secure shell): Starke Authentisierung, sicher Verbindung
• Bemerkung:
Eine Alternative zu Shellskripts für komplexere Aufgaben ist Perl
• Uebersichtliche Programmiersprachkonstrukte
• Verfügbar sowohl unter Windows/WSH als auch unter Unix/Linux
Shellprogrammieren mit Bash
Eigenschaften: Unix Shells
sh
bash
ksh
csh
tcsh
Ursprung
„das
GNU
Original“
System
5 R4
BSD
BSD
Unterliegende Syntax
sh
sh
sh
csh
csh
Job Kontrolle
-
+
+
+
+
Brauchbares I/O Redir +
+
+
-
-
Kommando History
-
+
+
+
+
Kommandozeile
editierbar
-
+
+
-
+
Dateinamen
Vervollständigung
-
+
+
+
+
Eingebaute Arithmetik
-
+
+
+
+
Shellprogrammieren mit Bash
Shellpgm: Variablen I
• Skalare Variablen
–
–
–
–
Definition: name=value
Zulässige Variablennamen
Zugriff: $name bzw. echo $name(Variable Subst.)
Zugriffsrechte: readonly name
• Bash/Korn: Array Variablen
–
–
–
–
Defintion; name[index]=value
Alloziert nur für belegte Indices, ksh: index in 0,..,1023
Initialisierung: Bash: name=(value1 ... valuen)
Zugriff:
• 1 Element: ${name[index]},
• Alle: ${name[*]} oder ${name[@]} wenn Elemente Leerzeichen enthalten
– Zugriffsrechte: readonly name
Shellprogrammieren mit Bash
Shellpgm: Variablen II
• Variablen freigeben
• Unset name (nicht für readonly Variablen)
• Scope von Variablen
• Lokale Variablen
• Environment Variablen
» Export name;
• Shell Variablen (von der Shell gesetzt)
» PWD,UID,SHLVL,IFS,PATH,HOME
Shellprogrammieren mit Bash
Substitution (Shell Preprocessing)
• Dateinamen Substitution (Globbing)
– * (Wildcard: suffix,prefix match),?,[a-zA-Z0-9 ],[!...]
• Value-based variable substitution (Tabelle machen!)
– Default zurückgeben falls Variable leer: ${parameter:-word}
PS1=${HOST:-localhost}"$ " ; export PS1 ;
– Variable mit Default belegen leer: ${parameter:=word}
– Abbruch mit message falls Variable leer: ${parameter:?message}
: ${HOME:?"Your home directory is undefined."}
– Default zurückgeben falls Variable gesetzt: ${parameter:+word}
echo ${DEBUG:+"Debug is active."}
• Command substitution
– ´command´
DATE=´date´; USERS=´who | wc -l´; UP=´date ; uptime´
• Arithmetic substitution
– Bash, Korn: $((expression))
foo=$(( ((5 + 3*2) - 4) / 2 ))
Shellprogrammieren mit Bash
Shellpgm: Quoting
• Quoting: Abschalten der Spezialbedeutung von sogenannten
Metazeichen:
* ? [ ] ' " \ $ ; & ( ) | ^ < > new-line space tab
alle anderen Zeichen (Literale) werden nicht beeinflusst
• backslash ( \)
– Escaping = Substitution für den nächstes Zeichen ausschalten
echo You owe \$1250
• single quote ( ')
– Substitution für alle Zeichen ausschalten
echo '<-$1250.**>; (update?) [y|n]'
• double quote ( ")
– Substitution ausschalten bis auf Variablen- und Kdosubst.
echo "$USER owes <-\$1250.**>; [ as of (´date
+%m/%d´) ]"
Shellprogrammieren mit Bash
Shellpgm: Quoting
•
Regeln
–
–
–
Backslash zwischen Doublequotes ist nur speziell für folgende Zeichen: $ „ ‚ \
Quoting ignoriert Wortgrenzen
echo Hel"lo; w"orld
Verschiedene Quoting Methoden dürfen in einem Kommando kombiniert werden
echo The '$USER' variable contains this value \> "|$USER|"
–
Leerzeichen zwischen Argumenten sind ein Trenner
echo Name
Address
echo „Name
Address“
mailx -s "Meeting tomorrow" fred jane < meeting.notice
–
–
Zeileende kann mit Backslash gequotet werden
$ cp file1 file2 file3 file4 file5 file6 file7 \
> file8 file9 /tmp
Argumente, die Wildcards oder Escapesequenzen enthalten müssen gequotet werden
•
•
•
•
Quotes benützen wenn auf ein File, welches Metazeichen enthält, zugegriffen werden soll
rm 'ch1*'
Reguläre Ausdrücke immer quoten
grep '[0-9][0-9]*$' report2 report7
Escape Sequenzen werden mit gequotetem Backslash bilden
echo -e "Line 1\nLine 2"
Wildcards für cpio und find müssen gequotet werden:
cpio -icvdum 'usr2/*' < /dev/rmt0
find / -name 'ch*.doc' -print
Shellprogrammieren mit Bash
Shellpgm: Test build-in
• Test expression oder [ expression ] schafft
Voraussetzung für die Flusskontrolle z.B. mit if oder case
– Filetests
-d
Ist Verzeichnis
-e
Existiert
-f
Existiert und ist reguläres File
-rwx
Ist les-, schreib-, ausführbar
Interaktives Bsp.: test -d $HOME; echo $?
[ -d $HOME ];echo $?
Shellprogrammieren mit Bash
Shellpgm: Test build-in
– Stringvergleiche
• -z, -n (String ist leer, nichtleer)
• =, != (2 Strings sind gleich, ungleich)
• Bsp.:
[ -n "$FRUIT_BASKET" ]
[ "$FRUIT" = apple ]
– Numerische Vergleiche
• Syntax: [ int1 operator int2 ]
• -eq, -ne, -lt,-le,-gt, -ge
– Zusammengesetzte Ausdrücke
•
•
•
•
•
!
E1 –a e2
E1 –o e2
Conditional Operators: e1 && e2, e1 || e2
Bsp
[ -z "$DTHOME" ] && [ -d /usr/dt ]
[ -z "$DTHOME" -a -d /usr/dt ]
test ! -d $HOME/bin && mkdir $HOME/bin
Shellprogrammieren mit Bash
Flusskontrolle: if
•
Basic Syntax
if list1
then list2
elif list3
then list4
else list5
fi
•
Unterschiede zu C/Java
– Es werden keine Klammern um Anfang und Ende
der Expression (list1) und der statements (list2, …, list5) anzgeben. Die
Funktionalität der Klammer wird komplett durch die Schlüsselworte if, elif, else
und fi übernommen.
•
•
•
•
•
then wird benötigt
( ;) vor dem then wird benötigt, falls dies nicht auf einer separaten Zeile steht
elif anstatt else if
fi am Ende des if statements
Bsp
if uuencode koala.gif koala.gif > koala.uu ; then
echo "Encoded koala.gif to koala.uu"
else
echo "Error encoding koala.gif"
fi
Shellprogrammieren mit Bash
Flusskontrolle: case
• Basic Syntax:
case word in
pattern1) list1 ;; <- Doppelstrichpunkt
pattern2) list2 ;;
esac
• Bsp::
FRUIT=kiwi
case "$FRUIT" in
apple) echo "Apple pie is quite tasty." ;;
banana) echo "I like banana nut bread." ;;
kiwi) echo "New Zealand is famous for kiwi." ;;
esac
Shellprogrammieren mit Bash
Flusskontrolle: While
• Begriffe: loop, body, iteration, nested loop, infinite loop
• Syntax
•
•
while command
do
list
done
Command kann irgendein UNIX Kdo sein, oft: test expression
Bsp.:
RESPONSE=
while [ -z "$RESPONSE" ] ; do
echo "Enter the name of the … directory:\c "
read RESPONSE
if [ ! -d "$RESPONSE" ] ; then
echo "ERROR: Please enter a directory pathname."
RESPONSE=
fi
done
• Schachtelung (Nesting) möglich
• Analog: until Kommando
Shellprogrammieren mit Bash
Flusskontrolle: For
• Basic Syntax
for name in word1 word2 ... wordN
do
list
done
• Bsp.
for FILE in $HOME/bin/* ; do
cp $FILE ${HOME}/WWW
chmod a+r ${HOME}/WWW/${FILE}
done
Shellprogrammieren mit Bash
Select
•
Ksh, bash: select -> Auswahlliste anzeigen
Syntax:
select name in word1 word2 ... wordN
do
list
done
•
Antwort steht in $REPLY
Bsp (üblich bei Softwareinstall Skripts):
select COMPONENT in comp1 comp2 comp3 all none
do
case $COMPONENT in
comp1|comp2|comp3) CompConf $COMPONENT ;;
all) CompConf comp1; CompConf comp2; CompConf comp3
;;
none) break ;;
*) echo "ERROR: Invalid selection, $REPLY." ;;
esac
done
Shellprogrammieren mit Bash
Flusskontrolle: Loop Control
• Break „exit loop“
– Syntax break [level]
– Bsp.: infinite loop
while :
do
read CMD
case $CMD in
[qQ]|[qQ][uU][iI][tT]) break ;;
*) process $CMD ;;
esac
done
• Continue „exit current iteration“
– Bsp.:
for FILE in $FILES
do
if [ ! -f "$FILE" ] ; then
echo "ERROR: $FILE is not a file."
continue
fi
# process the file
done
Shellprogrammieren mit Bash
Ein-/Ausgabe Umleitung
• Uebliche Voreinstellungen
• Standardeingabe: Tastatur (entspricht Dateideskriptor 0)
• Standardausgabe: Bildschirm (entspricht Dateideskriptor 1)
• Standardfehlerausgabe: Bildschirm (entspricht Dateideskiptor 2)
• Einfache Umleitungen
• < Datei anlegen, Eingabe umleiten
• > Ausgabe umleiten
• >> Datei anlegen, falls nicht existent, Eingabe anhängen
» Bsp.: sort namen.txt > sortierteNamen.txt
• Umleitung mit Filedeskriptoren
•
•
•
•
<& fd – assoziiere Filedeskriptor fd mit der Eingabe
>&fd – assoziiere Filedeskriptor fd mit der Ausgabe
Zwei Filedeskriptoren aufeinander umleiten: fd1>&fd2
Filedeskriptor schliessen: fd>&» Bsp.: mypgm 1>mypgm.txt 2>&1 (Reihenfolge wichtig!)
Shellprogrammieren mit Bash
Bsp: Umleitung der Eingabe
•
Mail von der Kommandozeile aus versenden:
mailx [email protected] < Exam_Answers
•
Ein paar URLs auf dem Standarddrucker ausgeben
lpr << MYURLS
http://www.hsr.ch/~fiedler/
http://www.cisco.com/
http://www.marathon.org/story/
http://www.gnu.org/
MYURLS
Hinweis: Eingabe Umleitung kann mit Ausgabe Umleitung kombiniert werden.
•
Bsp: root Einträge aus /etc/passwd auslesen:
while read LINE do
case $LINE in
*root*) echo $LINE ;;
esac
done < /etc/passwd
Shellprogrammieren mit Bash
Bsp.: Umleitung der Ausgabe
• Einfaches Bsp.:
date > now
{ date; uptime; who ; } >> mylog
• Bildschirmausgabe eines Programms zusätzlich in einem File
loggen
benütze das Tee Kommando
– Syntax: command | tee file
if [ "$LOGGING" != "true" ] ; then
LOGGING="true" ; export LOGGING ;
exec $0 | tee $LOGFILE
fi
Shellprogrammieren mit Bash
Bsp.: Umleitung mit Filedeskriptoren
– Hier einfacheres, eingängiges Bsp. Suchen !!!
Bestimmen, wie viele Zeilen in einem Textfile sind
i=0;
while read LINE ; do
i=´echo "$i + 1" | bc´
done < $file
echo $i
löst das Problem nicht, da die while Schleife in einer Subshell ausgeführt wird
und $i hinterher nichtmehr bekannt ist.
Vorschlag:
exec 3<&0 <$file # stdin sichern und File über stdin einlesen
i=0
while read LINE ; do
i=´echo "$i + 1" | bc´
done
echo $i
exec 0<&3 3<&- # stdin wiederherstellen, SicherungsFD schliessen
Shellprogrammieren mit Bash
Shellpgm: Parameter
• Syntax für Programmaufruf
command options <weitere Argumente>
• Options sind spezielle Argumente, die das Verhalten des Programms
verändern
• Spezielle Variablen
• $0: pgmname, $1 – arg1, $2 – arg2, …, $#: Anz. Args
• $*: Alle Argumente insgesamt double quoted
– Vorsicht: mytar -t "my tar file.tar„
– Mit shift kann das jeweils erste Argument weggeworfen werden.
• $@: Alle Argumente einzeln double quoted
• $? Exit status des letzten Kommandos
• $$: PID of current Shell
• $!: PID des letzten Hintergrundkommandos
• Behandeln von Optionen
• Case statement
• Getopts
Shellprogrammieren mit Bash
Shellpgm: Optionen abarbeiten
• Einfaches Bsp.: Abarbeiten von Optionen mit case statement
$cat mytar
USAGE="Usage: `basename $0` [-c|-t]
[file|directory]„
if [ $# -ne 2 ] ; then
echo "$USAGE" ; # Usage statement ausgeben
exit 1 ;
fi
case "$1" in
-t) TARGS="-tvf $2" ;;
-c) TARGS="-cvf $2.tar $2" ;;
*) echo "$USAGE" exit 0 ;;
esac
tar $TARGS
Shellprogrammieren mit Bash
Shellpgm: Option Parsing
•
•
Falls es eine grössere Anzahl Optionen gibt: getopts
Syntax: getopts option-string var
–
getopts untersucht alle Kommandozeilenargument und sucht nach
Argumenten, welche mit – beginnen
–
–
–
Diese werden, falls gefunden, mit dem option-string verglichen
– Bei Uebereinstimmung
– wird die zu die Option in der Variablen var gesetzt
– Ein evtl. gefundenes Argument steht in die Variable OPTARG
– Bei Nicht-Uebereinstimmung wird die Variable var auf ? gesetzt.
Dies wird wiederholt bis alle Argument abgearbeitet sind
Danach
–
–
gibt getopts einen Exit Code zurück der von 0 verschieden ist
– Daher kann getopts einfach in Schleifen (Loops) eingestetzt werden.
Die Spezialvariable OPTIND steht auf dem Index des letzten Arguments
– Dadurch kann auf weitere Argumente, die keine Optionen enthalten,
einfach zugegriffen werden
Shellprogrammieren mit Bash
Bsp.: Option Parsing
• Bsp: Es sollen eine verbose Option geben und mit Optionen soll
auch ein infile und ein outfile gestetzt werden können
• getopts v:i:o OPTION
• VERBOSE=false
while getopts v:i:o OPTION ; do
case "$OPTION" in
v) VERBOSE=true ;;
i) INFILE="$OPTARG" ;;
o) OUTFILE="$OPTARG" ;;
\?) echo "$USAGE" ;
exit 1 ;;
esac
done
• Weitere Argument abarbeiten
shift `echo „$OPTIND -1“ | bc`
Nun ist $1 das erste verbleibende Argument
Shellprogrammieren mit Bash
Funktionen
• Name für eine Liste von Shellkommandos: Subroutine, Prozedur
mit eigenen Argumenten und Exit code
• Funktionen laufen der Shell ab, in der die Funktion aufgerufen wird
• Syntax:
Definition: name ( arg1 .. argN ) { list ; }
• auf arg1 .. argN kann innerhalb der Funktion mit $1 .. $N und $@
zugegriffen werden
• Alle anderen lokalen Variablen haben global scope (anders als bei Subshell!)
• Return Code 0: Erfolg, >0: Fehlerfall
Aufrufs: name arg1 .. argN
• Interpreter parst die Definition auf Syntax Errors
• Interpreter trägt den Funktionsnamen in die Liste der Shell
Kommandos ein
• Funktion ist dann im Skript/Shell und in allen Subshells bekannt
• Löschen aus der Liste der Shell Kommandos mit: unset name
Shellprogrammieren mit Bash
Bsp.: Funktionen
– Definitionen einer Funktion zur Emulation von Aliases
(alternativen Namen):
Definition:
source() { . "$@" ; }
cd () { chdir ${1:-$HOME} ; PS1="´pwd´$ " ; export PS1 ; }
Aufruf:
source myshellskript.sh ; cd /home/fiedler/mydir
– Definition einer Funktion welche die Verzeichnisse PATH im Pfad nur setzt,
falls benötigt (Anwendung: Gebrauch desselben Login-skripts auf
verschiedensten Maschinen)
SetPath() {
for _DIR in "$@" ; do
if [ -d "$_DIR" ] ; then PATH="$PATH":"$_DIR" ; fi
done
export PATH
unset _DIR
}
Shellprogrammieren mit Bash
Texte filtern: Head, Tail, Grep
•
•
Shellskripts müssen oft Ausgaben umformatieren, manipulieren etc.
Head: Fileanfang ausgeben
– Syntax: head [–n lines] file/filelist
– Bsp.: die 5 Files im Home-Verzeichnis,
auf die zuletzt zugegriffen wurde auflisten
ls -1ut /home/fiedler | head -5
•
Default n=10
Tail: Fileende ausgeben
– analog zu head
– zusätzlich follow Option: tail –f file/filelist
•
Global regular expression print: Grep
– Datei auf Zeilen, die ein Wort/Wortgruppe/Regulären Ausdruck enthalten
absuchen und diese ausgeben
– Syntax: grep options reg.exp. File/filelist
– Bsp.: grep –i pipe ch15.doc -- -i: Case insenstive
grep –v ‚#‘ /etc/host -- -v: suche auf Zeilen, die das
Wort/Wortgruppe/Regulären Ausdruck nicht enthalten
grep –n ‚myvar‘ pgm.cc -- -n: Zeige Zeilennr an
grep –l ‚myvar‘ *.cc -- -l: Zeige nur Dateiname an
Shellprogrammieren mit Bash
Texte filtern: tr, sort, unique
• Transliterate: tr
– Zeichen ersetzen
– Syntax: tr options ´set1´ ´set2´
– Bsp.: Kleinbuchstaben durch Grossbuchstaben ersetzen:
tr ´a-z´ ´A-Z´
Mehrfachleerzeichen durch eines ersetzen (squeeze):
tr –s ´ ´
Alle Trennzeichen einer Datei durch Leerschlag ersetzen:
cat file | tr ´[:punct:]´ ´ ´ | tr ´[:space:]´ ´ ´ | …
• Sortieren: sort
– Syntax: sort options file
– Bsp: sort –rn -- -n numerisch, -r: reverse (umgekehrt)
sort –k 2,2 -- -k: Sortierschlüssel (Key) ist die 2. Spalte
• Unique: uniq
– Alle Zeilen nur 1x ausgeben, auch mehrfach vorkommende
– Syntax: uniq option
– Bsp: Unique –c file -- -c: Häufigkeit der Zeilen mitangeben
Shellprogrammieren mit Bash
Reguläre Ausdrücke
• Beschreiben eine Menge von Strings
• Werden oft verwendet um Texte zu suchen, zu filtern oder zu
editieren
– Z.B. bei einer Suche mit grep
• Aufbau:
– normale Zeichen: A-Z,a-z,0-9, usw.
– Metazeichen:
Irgendein Zeichen ausser Newline
.
*
0 oder mehrmalsl das Zeichen davor
[ chars ]
Irgendein Buchstabe der Menge chars
- : Buchstabenintervalle z.B. A-Z
^
Zeilenanfang
$
Zeilenende
\
Metabedeutung ausschalten
Shellprogrammieren mit Bash
Reguläre Ausdrücke: Bsp.
• Wildcard
• /a*c/ matcht mit ace, yacc, arctic, „close the window“
• Greedy match
• /a*a/ matcht mit „able was I, I saw elba“
• Mengen von Buchstaben
• /[tT]he/ matcht mit „the“ und „The“
• Reversing
• /^T/ matcht alles ausser T
• Anchoring
•
•
•
•
/^the/ matcht „the“ am Zeilenanfang
/friends$/ matcht „friends“ am Zeilenende
/^$/ matcht Leerzeilen
/^.*$/ matcht beliebige ganze Zeile
• Quoting
• /\$[0-9]*\.[0-9][0-9]/ matcht mit irgend einem Dollar Betrag
Shellprogrammieren mit Bash
SED
•
•
•
Zeilenweise einlesen, kopieren, bei pattern matching action auf Kopie anwenden
Geeignet für kleine Editieroperation z.B. in einer Pipeline
Syntax: sed options ´script´ file
–
•
Script: /regulärer Ausdruck/ action
»
Action: p (print): Zeile kopieren und bei Match nochmals ausgeben
Options: -n (noduplicate)
d (delete), Zeile bei Match löschen
s/reg. Ausdruck2/reg. Ausdruck3/qualifier (substitute)
bei Match reg. Ausdruck2 durch reg. Ausdruck3 ersetzen
& Operator in reg. Ausdruck 3: paste das, was im reg. Ausdruck2
gematcht hat
Bsp.:
–
–
–
alle Zeilen die HSR enthalten löschen:
mv file1.txt file1.txt.$$
sed ´/HSR/d´ file1.txt.$$ > file1.txt
Ueberall „Ulrich Fiedler“ durch „Dr. Ulrich Fiedler“ ersetzen
mv cv.txt cv.txt.$$
sed s/Ulrich Fiedler/Dr. Ulrich Fiedler/g cv.txt.$$ > cv.txt
da ein erster regulärer Ausdruck fehlt matchen alle Zeilen
der Qualifier g (global) bewirkt, dass „Ulrich Fiedler“ nicht nur beim ersten Mal ersetzt wird sondern immerl
Ueberall ein $ Zeichen vor den Preis hängen
sed ´s/*[0-9][0-9]*\.[0-9][0-9]*/\$&/´ preisliste.txt
Shellprogrammieren mit Bash
Zusammenfassung
Shellprogrammieren mit Bash

Bsp - Lugs