orm@doc-tcpip.org

Erstellt: November 1999 - Letzte Modifikation: März 2009

[ Main | Local ]


Merkzettel zur Shellprogrammierung


 
$? Fehlercode der Rückgabe ==> 0 ist OK
set -e / +e wertet Fehlercode aus und steigt dann aus.
set -o errexit / +o errexit

Nutzt man zum debuggen:
sh -e 
sh -x           mit -x sieht man alle Nachrichten
oder in das Skript eintragen als set -x.

Fehlercodes über 128:
Das Programm wurde durch ein Signal beendet.
Signalnummer + 128, Bsp. kill -9 ==> 137 (128 + 9)

if Schleife mit nur 1. Bedingung: 
einsatz von Operatoren && und ||möglich.

&& wenn Bedingung erfüllt ==> Bing
|| wenn Bedingung nicht erfüllt ==> Bing


Conditions testen:
[[ $x = y ]]    ==>  wenn $x == y Rückgabe 0
[[ $x != y ]]    ==>  wenn $x == y Rückgabe 1

[[ $x = *pub* ]] ==> Ist in $x "pub" enthalten?

Wenn $x aus mehreren Worten besteht: "$x"
Wenn am Anfang ein - steht: x'$x' = xy
oder
[[ $x = y ]]

Vergleich Variable (String) mit String:
$VAR ist gleich "Seppel"
if [[ $VAR = "Seppel" ]]; then ...

Einen Rückgabewert erzeugen bzw. in eine Variable einlesen:

lsdev -Cl dpo | wc -l | read DPO
später auslesen:
if [[ $DPO -gt 0 ]]
then
...
Gibt in diesem Fall eine Zahl, man kann auch direkt einlesen
und erhält einen String.

Bei einem File mit mehreren Zeilen mit while-Schleife:
cat delete | while read DPO; do echo $DPO; done

User Input lesen:
echo -b 'Dein Name?' >&2   #Prompt geht nach STDERR
read NAME
echo "Dein Name ist $NAME"

Schleifen

Zählen von 0 bis 12:

 
for i in `seq 0 12`
   do
     blablabla
   done

oder:

 
i=0
while [ $i -le 12 ]
   do
      blablabla
      i=$((i+1))
   done

oder nicht portabel:

 
while (( i<=12))
   do
      blablabla
      i=$((i+1))
   done

oder nicht portabel:

 
for ((i=0; i <= 12; i++))
   do
     blablabla
   done

Schleifen und Unterbrechungen

 
while true
   do

      condition && break
   done

Wenn die Kondition wahr ist, dann wird mit break unterbrochen.
Mit ||: wenn die Kondition falsch ist, dann mit break.

Mit break: Hinter der Schleife wird das Programm fortgesetzt. Mit continue: Sprung an den Beginn der Schleife.

Variablenhandling

${rmt#rmt} ==> von der Variable rmt den Teil mit rmt weg schneiden.
var=${var:=xxxx} ==> wenn die Variable var nicht gesetzt ist, dann dafür xxxx setzen (setzt also Defaults).
rmt="rmt$i" ==> Variablen mit Variablen kombinieren.
${name##*/} ==> Nimmt den Pfad von einem Filenamen.
${name%/*} ==> Nimmt den Namen und läßt den Pfad.
Generell nimmt % von Rechts Zeichen weg, und # von Links.
Mit %% und ## nimmt man den längsten möglichen Match, sonst den kürzesten.
Ein Beispiel:

echo $LIST
_MGP0580.JPG _MGP0581.JPG _MGP0582.JPG _MGP0580589.JPG _MGP0590.JPG _MGP0591.JPG 

Macht daraus IMG*:

 for i in $LIST; do  mv $i I${i##*_}; done

Rechnen in der Shell

i=$(($i + 2))

File Descriptoren

Pro Prozess 3 Stück per Default: 0 STDIN
1 STDOUT
2 STDERR
(Man kann mehr öffnen, klar.)

 
2> /dev/null ==> schiebt Fehlermeldungen (STDERR) nach
/dev/null

2>&1  ==> schreibt STDERR dahin, wo STDOUT schon hingeht
(Kombiniert Umleitung 2> mit Einleitung >&1)
 
cat xxx 2>&1 > file ==> geht nicht!!
cat xxx > file 2>&1 ==> geht!!

Die Shell liest von links nach rechts.

2>&1
heißt: 2 soll dahin gehen, wo 1 schon hingeht. Im 1. Fall: zum Terminal. Das ist aber schon umgeleitet. Daher geht nur der 2. Fall: 1 wird in ein File umgeleitet, und 2 wird dahin gelenkt, wo 1 schon hingeht.

HERE Dokumente

Etwas von STDIN lesen, ohne dafür ein File zu öffnen: Man muß sich ein Wort als Kennzeichnung für das Ende des Datenstromes aussuchen - was nicht schon im Strom stehen darf.

 
sort > file < 
 
cat > file <  

Will man keine Substitution spezieller Character:

 
cat > file <<\EndOfFile

Kommandoausführung

 
. File => ausführen in der Shell.
$< vom Terminal Input lesen
( cmd;cmd ) => cmd;cmd in Subshell (sh)
{ cmd;cmd } => cmd;cmd ohne Subshell (sh)
>| file ==> Ausgabe in File, auch wenn noglobber gesetzt ist.
<<-Wort ==> lesen bis "Wort", Tabs ignorieren

Umleiten

 
m > file     Umleiten von m => file
m >> file    Anhängen der Daten
m < file     Umlenken der Eingabe 
<&m          m als STDIN        
<&-          STDIN schließen 
>&m          m als STDOUT   
>&-          STOUT schließen
m <&n        Verbinden des Input-Files n mit File m
m <&-        m schließen
n >&m        Verbinden des Output-Files n mit File m
m >&-        Schließen von m

vi Mode Kommandos

 
~ Groß- und Kleinschreibung für aktuelles Zeichen tauschen.
_ letztes Wort des vorhergehenden Kommandos ablösen.
CTRL-L Clear Screen, neuschreiben der aktuellen Zeile
# ....  Zum Einsetzen von Kommentaren in das History-File

Kommandozeilen kompletieren

 
TAB
CTRL-x    Kompletieren des User-Name
CTRL-x /  Liste
ESC ?     Liste der möglichen Befehle
ESC \     Kompletieren von Dateinamen
ESC ~     Kompletieren des User $HOME
ESC $     Kompletieren von Variablen
ESC @     Kompletieren von Hostnamen
ESC !     Kompletieren von Befehlen
ESC TAB   Kompletieren mit vorherigem Befehl aus der History

Quotes, Abschalten der spez. Zeichen

Quoting schaltet die speziellen Eigenschaften von Zeichen ab.

 
Single Quote: ' 
Double Quote: "
Backslash: \

Der ` Backquote ist kein Quoting Charakter! Er macht Kommandosubstitution!

 
Spezielle Charakter: # & * ? [ ] ( ) = | ^;<>`$ "' \
'        '  Alle speziellen Charakter sind jetzt tot.
==> Single Quotes in Single Quotes sind deshalb sehr
dumm, weil so eine Lücke entsteht.

"        "  Alle speziellen Charakter bis auf $ ` \ sind tot.
\           Der folgende Charakter ist tot.

Wichtig beim umbenennen/löschen dummer Filenamen:

 
mv a\ file a_file
mv 'a file' a_file 

Kommando Wiederholung

 
!!        letztes Kommando
!:        letzte Kommando mit Modifikation
          !:s/mein_file/deinfile/
          (Geht mit jedem Charakter als Delimiter:
          !:s:mein_file:deinfile:)
!-2       vorletztes Kommando
!so       letztes Kommando, das mit "so" begann
!?fn?     letztes Kommando, das "fn" enthielt
!34       Kommando Nummer 34 in History-Liste
!! &      fügt an letztes Kommando ein Ampersand an
!! |more
!! > file_out
!m:p      zeigt letztes Kommando
          (Generell printet :p das Ergebnis aus. Dann kann man
          z.B. !! machen).
!:0       letztes Kommando ohne Parameter ausführen

Man kann einzelne Argumente wählen:

 
cat x1 x2 x3 

more !:3    ==> more x3
more !:2-4
more !^     ==> erstes Argument
more !$     ==> letztes Argument
!$          ==> letztes Wort von der letzten Zeile
!:n*        ==> Argumente n bis Zeilenende

Oder Teile des Befehles:

 
chmod 777 x1 x2 x3 x4

vi !:4*     ==> vi x2 x3 x4
!ch:2*      chmod Befehl ab dem zweiten Argument
!:2*        letzter Befehl ab dem zweiten Argument

Tippfehler kann man auch korrigieren:

 
cat mien_file => Tippfehler
^ie^ei        => Wird so berichtigt ausgeführt.

Mit ^^ kann man jedes Kommando anpassen.

Mit ^ kann man auch löschen:
moore mein_file ==> ^o

Die allgemeinen Shellvariablen sind of auch nützlich:

 
ls ai* 
=> file1 file2 .....
rm !$   ==> und alle weg....

SED

Mehrere Substituierung nacheinander:

 
sed -e 's/xxx/yyy/' -c '/zzzz/vvvv/' file
sed 's/xxx/yyy/;s/zzz/vvv/' file

Man kann die gewünschten Aktionen auch in ein File zusammenfassen:

 
sed -f skriptfile file

Im Skriptfile die Anweisungen, z.B. :

sed '
s/xx/yy/
s/zz/vv/' 

Das kann man in der Bash auch direkt Zeilenweise eingeben. Die meisten Shells werten einen Newline Charakter als Kommandoende.

 
Alles in ein File leiten (Ausgabeumleitung):
exec >> $File_Name 2>&1

Greppen:
(egrep -v '^  [01] | partially') < $File_Name > $File_ausgabe
Unterdrückt alle Zeilen, die mit 2. Leerstellen und als 
3. Stelle entweder 0 oder 1 beginnen ODER den String 
"partially" enthalten.
# Filter:
if [ -z "$(echo $dev | grep ^#)" ] && [ .... ]; then
Beide müssen TRUE sein...
echo Kommando Schalter:
echo -e Backslash escaped Characters werden interpretiert.
echo -E Backslash escaped Characters werden nicht interpretiert (Default).
echo -n Newline am Zeilenende wird ignoriert.

Escape Sequenzen:
\a ALERT CTRL G
\b BACKSPACE CTRL H
\c IGNORE NEWLINE
\f FORMFEED CTRL L
\n NEWLINE CTRL J
\r ENTER CTRL M
\t TAB CTRL I
\v VERTICAL TAB CTRL K
\0n ASCII CHAR (n ist ein Oktal-Wert)
\\ Backslash....

Rechnen mit der Shell - Integer Arithmetik

$(( .... ))
Variablen in einem arithmetischem Ausdruck müßen nicht
mit $ angegeben werden. Arithmetische Ausdrücke wie in 
C-Operatoren.

+ Plus
- Minus
* Mal
/ Teilen
% Rest (Modulo)
<< Bit Shift
>> Bit Shift
& Bitweise und
| Bitweise oder
~ Bitweise nicht
! Bitweise nicht
^ Exclusives nicht

Relative Operatoren
< kleiner
> größer
<= kleiner gleich
>= größer gleich
== gleich
!= nicht gleich
&& logisch und
|| logisch oder

Exponentialzahlen:
10 Hoch 3 ==> 10#3
B#N bis N == 36

Die Korn-Shell hat eingebaute arithmetische Ausdrücke.
Damit kann man prima rechnen.
Das geht so:

summe=$((34 + 3.5))  oder
(( summe = 34 + 3.5))

Dazu gibt es alle mathematischen Funktionen, die das Herz begehrt:

sqrt    ==> Quadratwurzel ziehen
log     ==> Logarithmus
exp     ==> Exponent zur Basis 10
int     ==> 
abs     ==> Absolutwert 
sin     ==> Sinus
sinh    ==>
asin    ==> 
cos     ==> Cosinus
cosh    ==>
acos    ==> 
tan     ==> Tangens
tanh    ==>
atan    ==>

So kann man auch Konstanten berechnen:
(( pi = 4.0 * ( 4.0 * atan(1.0/5.0) - atan(1.0/239.0) ) ))

$ echo $pi
3.14159265359

Jetzt kann man allerlei rechnen:
radius=55
umfang=$((2 * pi * radius))

$ echo $umfang
345.575191895

flaeche=$((pi * radius * radius))


[ Main | Local ]

[ Allgemein | UNIX | AIX | TCP-IP | TCP | ROUTING | DNS | NTP | NFS | FreeBSD | Linux | RPi | SMTP | Tracing | GPS | LW ]

Copyright 2001-2021 by Orm Hager - Es gilt die GPL
Feedback bitte an: Orm Hager (orm@doc-tcpip.org )