Shell-Scripting HowTo

Kamikaze

Warrior of Sunlight
Teammitglied
Das Wiki hat inzwischen ein Shell-Scripting HowTo. Ich würde mich freuen, wenn sich der Eine oder Andere das mal ansieht und Hinweis gibt, wo ich mehr in die Tiefe gehen sollte und wo Dinge noch unklar sind.

Ich wollte mich irgendwann noch in NetCat einarbeiten, das würde ich dann auch noch dazu basteln.
 
Gute Idee!

Kleine Anmerkungen:

1.) In printf-Formatstrings ist '\r' der Wagenrücklauf, '\c' hingegen verwirft den Rest des Strings.
2.) Vielleicht erwähnen, dass '$(...)' geschachtelt werden kann, Backticks jedoch nicht.
 
@danlei
Das mit \c war ein Fehler, ich habe \r gemeint. Vielen dank, ich baue jetzt beides noch ein.
 
Gute Arbeit erstmal, ich denke aber, viele Beispiele sind fuer Einsteiger etwas komplex :)


Bei der Redirection wuerde ich anmerken, dass auch folgende Syntax tut (das verwundert den ein oder anderen beim Lesen)

Code:
% > foo echo hello
% < foo cat
hello
% < foo > bar cat
%


Dann wuerde ich anstelle von expr(1) lieber direkte Shellarithmetik mittels $(( $i + 1 )) verwenden (ist IMHO lesbarer). Wer richtig was Rechnen will, sollte sich dc(1) und bc(1) ansehen.

Ein Beispiel verwendet "sed foo | sed bar", dass kann man "besser" lösen mit "sed -e foo -e bar" oder gar "sed -e 'foo; bar'".

Bei den Schleifen koennte man vielleicht noch erwaehnen, dass ohne Angabe einer expliziten Liste die postionalen Parameter verwendet werden:

Code:
for i; do
 echo $i   # Gibt $1, $2, $3 .. einzeln aus
done

Und, dass diese mit "set" gesetzt werden können (ist hilfreich, um default Parameter zu setzen:

Code:
test $# -lt 1 && set -- foo bar baz
for i; do
  echo $i
done

Die einzige uneingeschränkt funktionierende Methode mit Leerzeichen in Dateinamen umzugehen ist die Änderung des IFS (Input Field Seperator).

Das ist falsch, es reicht naemlich nicht aus, IFS=\n zu setzen, da schliesslich auch Newlines in Dateinamen vorkommen können. Das einzig wahre Trennzeichen ist \0. Was man mittels "find -print0 | xargs -0" dann verarbeiten kann. (Laesst sich der IFS auf \0 setzen?)

Du solltest auch den -E Parameter fuer sed(1) nur dann verwenden, wenn du ihn brauchst. So machst du naemlich alle Beispiele unportable (-E ist IIRC nicht in POSIX).

Code:
if [ $2 ]; then
        ip=$2
fi

Urgs, in $2 kann Gott und die Welt stehen, und du uebergibst das spaeter ungeprueft wieder an die Shell weiter. Bitte Variablen quoten, also "if [ "$ip" ]; then" und ueberhaupt die Eingabeparmeter besser validieren.

Es fehlt auch noch ein Abschnitt ueber das "case" Statement und du solltest die sehr gute sh(1) manpage oefter referenzieren (zB die Liste unter 2.1, da solltest du auf http://www.freebsd.org/cgi/man.cgi?query=sh verlinken).
 
Danke für die Hinweise, ich pflege das demnächst ein. Die Shell-Arithmetik ist mir neu. Ich wusste nicht, dass das geht.
 
Als Shell-Newbie mal ne kleine Frage:

Könntest du vielleicht noch (unter Pipes, oder so) erklären, was & und && bedeuten? Ich hab noch nichts gefunden, wo das genau erklärt wird und hab da nämlich nur gefährliches Halbwissen. :(

&& = besagt das ein Befehl nur ausgeführt wird, wenn der vorige erfolgreich ausgeführt wurde ?

& = ?
 
&& = besagt das ein Befehl nur ausgeführt wird, wenn der vorige erfolgreich ausgeführt wurde ?
Soweit richtig. Wobei erfolgreich ausgeführt bedeutet, dass der Befehl den Exit-Code 0 zurückgegeben hat. Alles Andere würde dann als Fehler identifiziert.

Das führt den Befehl im Hintergrund aus.

Beides hat nichts mit Pipes zu tun und wird deshalb auch nicht dort erklärt.

Das & wird im Abschnitt Prozesse forken erklärt (da fehlt noch ein einfaches Beispiel).

|| und && gehören in den Bereich Programmfluss (if-then-else-Kram). Den habe ich schlichtweg vergessen. Deshalb, danke für den Hinweis! :D
 
Das ist falsch, es reicht naemlich nicht aus, IFS=\n zu setzen, da schliesslich auch Newlines in Dateinamen vorkommen können. Das einzig wahre Trennzeichen ist \0. Was man mittels "find -print0 | xargs -0" dann verarbeiten kann. (Laesst sich der IFS auf \0 setzen?)
Bist du dier sicher? Mir ist es nicht gelungen Dateien mit Newlines im Namen zu erzeugen.

Mir ist es auch nicht gelungen IFS auf \0 zu setzen:
Code:
IFS="$(dd bs=1 count=1 if=/dev/zero 2> /dev/null)"
Anscheinend wird die Null ignoriert, sie terminiert nicht mal den String:
Code:
#!/bin/sh
IFS="before$(dd bs=4 count=1 if=/dev/zero 2> /dev/null)behind"
echo "$IFS"
 
Bist du dier sicher? Mir ist es nicht gelungen Dateien mit Newlines im Namen zu erzeugen.

Code:
% mkdir /tmp/foo
% cd /tmp
% IFS=x
% touch `printf "foo/these\nare\nnewlines"`
% xxd foo|head -4
0000000: c160 0000 0c00 0401 2e00 0000 0200 0000  .`..............
0000010: 0c00 0402 2e2e 0000 c260 0000 e801 0812  .........`......
0000020: 7468 6573 650a 6172 650a 6e65 776c 696e  these.are.newlin
0000030: 6573 00c8 0000 0000 0000 0000 0000 0000  es..............
 
Das habe ich auch versucht, aber da kommen 3 Dateien raus, nicht eine mit Newlines drin.
 
Muss es nicht
$ touch "`printf "Bla \n Blubb"`"
heißen? Also in " ". Sonst bekommt man ja nur einzelne Dateien. Ich frage mich dann aber, ob er auch eine Datei, die nur ein newline char enthält anlegen kann? Mal ausprobieren. ^^
 
Mit
$ touch "`printf "Bla \n Blubb"`"
schließt sich mein Terminal. Es werden auch keine Dateien angelegt.

Mit
$ touch "`printf "Bla\nBlubb"`"
erhalte ich die Datei "BlanBlubb".

Mit
$ touch "`printf 'Bla \n Blubb'`"
erhalte ich die Dateien "Bla " und " Blubb".

Ich kann mir einfach nicht vorstellen, dass es Dateien mit Newlines gibt.
 
Mh komisch. Bei mir funktioniert das:
s-tlk /tmp > touch "`printf "BLA\nBLUBB"`"
s-tlk /tmp > ls BLA*
BLA?BLUBB
s-tlk /tmp > vi BLA'
'BLUBB

Wenn ich hier ein BLA<tab> mache, macht er mir ein newline.

Ich benutze die zsh als Shell mit der es geht. Aber mit der tcsh zb nicht. Sehr merkwürdig...
Mit der sh geht es zb. Versuch das mal. Vllt kommt man so dem auf den Grunde
 
Zuletzt bearbeitet:
Bourne Shell-Derivate:
touch 'bla[EINGABETASTE]blub'

C-Shell-Derivate:
touch 'bla\[EINGABETASTE]blub'
 
Ja, ich benutze tatsächlich die tcsh, mit Tron's Variante macht sie auch keinen Core-Dump mehr.

Der Befehl ls ersetzt mit einem ?, rm kommt damit gar nicht klar. Nur mit dem * Operator kann ich die Datei wieder löschen. Firefox listet die Datei mit dem Newline.

Da die Shell-Commandos damit klar kommen, müssen das meine Skripte eigentlich auch nicht. Das war eben übrigens die erste Datei mit NewLine meines Lebens und ich hoffe es bleibt die Letzte.

Denn IFS lässt sich nicht auf 0 umbiegen, damit ist das ganze dann nicht mehr skriptbar.
 
Zurück
Oben