• Diese Seite verwendet Cookies. Indem du diese Website weiterhin nutzt, erklärst du dich mit der Verwendung von Cookies einverstanden. Erfahre mehr

Anfängerfrage zur Shellscript-Variablengestaltung

Nonpareille

Well-Known Member
Themenstarter #1
Eine Frage an die Shellgurus

Vorab die Bitte um Nachsicht, meine Programmiererfahrungen sind mit "bescheiden" noch sehr beschönigend beschrieben.
ich habe mir ein kleines Script geschrieben, mit dem mein Fileserver (per Cronjob) alle paar min abfragt, ob überhaupt noch user angemeldet sind und das Ergebnis zur weiteren Verwendung in einer Variablen ablegt.
Nach mehreren vergeblichen Versuchen, habe ich dann ein im Internet gefundenes Beispiel aus einem Forum entsprechend abgeändert.

Code:
output=""
output=$(who $i)
Eigentlich ganz primitiv.
Mein Problem: Es funktioniert, d.h., $output enthält im Fall jemand ist angemeldet, den entsprechenden Eintrag.
Aber trotz Studium eines Handbuchs zur Shellprogrammierung und diverser Internetseiten zum Thema Shell ist mir nicht klar, warum es funktioniert.
Die Funktion von "who" ist bekannt.
Aber was bewirken die Dollarzeichen und die Klammern im konkreten Fall?
Wär es möglich, dass einer der Wissenden die zweite Codezeile mal aufdröselt? Mir würde auch schon eine Literaturstelle reichen, die sich explizit mit dieser Art der Variablengestaltung befaßt.
 

SierraX

Well-Known Member
#2
Ich bin mir jetzt nicht sicher wozu die output erst noch als leerer string definiert (ist in modernen shells nicht mehr nötig, es gibt ein paar script oder programmiersprachen wo man sowas tun muss) und wo das $i herkommt bzw was das soll. $i wird historisch für itterationen verwendet z.B. in einer for schleife... jetzt taucht für mich die frage auf warum dort der Standard Ort für diese informationen (bei OpenBSD z.B. /var/run/utmpx ) nicht als Quelle ausreicht.
<var>=$() ist das ausführen eines Programms oder einer Programmkette (z.B. wenn nur ein teil gebraucht wird) und übergabe von dessen STDOUT an die Variable. Man liest auch häufiger noch die `` (backticks) die im Grunde das gleiche machen.
Ich verwende $() meistens wenn ich ein Datum in einem bestimmten Format irgendwo in einem Script brauche... $(date +%Y%m%d) z.B.
Einer meiner Mentoren meinte einmal, $() löse einen einzelnen Prozess aus während die `` eine subshell also mehrer prozesse und problematiken mit lokalen Variablen (also das man die Variablen exportieren müsse wenn sie in den backticks Verwendung finden sollen) auslösen würden. Was ich aber nie versucht habe zu bestätigen oder dementieren.
 

Nonpareille

Well-Known Member
Themenstarter #3
Ganz großes Danke. Das hilft mir weiter. Und Du hast recht, $i ist hier unnötig bw. im weiteren Verlauf sogar schädlich. Dass ich die Variablen auf definierte Anfangswerte setze, stammt noch aus meinen letzten halbwegs ernsthaften Versuchen mit BASIC. Da war das noch notwendig.
 

TCM

Well-Known Member
#4
Backticks sind funktional identisch zu $(). Beide starten eine Subshell. Man sollte trotzdem $() bevorzugen, weil Backticks einfach scheiße aussehen und mit Apostrophen verwechselt werden können und nicht schachtelbar sind.
 

SierraX

Well-Known Member
#5
Das schöne am Shell scripting ist das man das meisste nicht erst in eine Datei schreiben muss um es dann zu kompilieren um danach den fertigen Blob ausführen zu können, sondern man macht das recht stressfrei innerhalb der Shell.
Gerade Variablen die mit einer Subshell befüllt werden kann man sich vorher anschauen bevor man irgendeinen schaden damit anrichtet
Gerade heute wieder bei mir...
also ich hab meinem ssh tunnelserver (extern gehosteter Server) 2 längst überfällige upgrades verpasst (von 6.1 auf 6.3) und da es mindestens einen Neustart verlangt verschwindet der Tunnelausgang für eine gewisse Zeit...
jetzt ist das Problem meine tunnelclients brechen damit die Verbindung ab und starten sie auch nicht mehr neu. Was bei tunnelclients die nicht in unmittelbarer nähe sind echt ärgerliche folgen hat. Vielleicht gibt es auch einen anderen, einfacheren Weg der ist mir aber (noch) nicht bekannt und da dachte ich mir halt, schreibst du ein script dass alle 5 minuten ausgeführt guckt, wird ob die Verbindung noch da ist.
Variable
Code:
tunstatus=$(ifconfig tun0 | grep -o "status:.*")

echo $tunstatus
status: active
Soweit so gut... allerdings

Code:
[ $tunstatus == "status: active" ]
ksh: [: active: unexpected operator/operand
anyway, test (der short cut []) verschluckt sich an dem Doppelpunkt, dem space danach oder beidem wenn man es nicht zu einem kompletten String verwurstet ( also "$tunstatus" statt $tunstatus innerhalb von test). Mit einzelnen Worten gibt es keine Probleme

Solche Sachen kann man wunderbar ausserhalb des Scripes testen. Man packt das ganze am besten erst als ganzes script zusammen, wenn die einzelnen komponenten auf der Shell funktionieren.
 

Nonpareille

Well-Known Member
Themenstarter #6
Vermutlich verschluckt sich test am space. Ich hatte bei der Weiterverarbeitung der obigen Variable das analoge Problem, dass das auf den Loginnamen folgende "ttyx" genauso angemeckert wurde. Da ist ja kein Doppelpunkt dazwischen. Ich hab dann mit cut den mich interessierenden Teil rausgeschnitten.
Code:
output=$(who|cut -c1-8)
Wenn da die letzten Zeichen Leerzeichen sind stört sich test offensichtlich nicht dran.
 
R

ralli

Guest
#7
Das schöne am Shell scripting ist das man das meisste nicht erst in eine Datei schreiben muss um es dann zu kompilieren um danach den fertigen Blob ausführen zu können, sondern man macht das recht stressfrei innerhalb der Shell.
Genau so ist es, und deshalb interessiert es mich sehr. Unter OpenBSD ist ja die Kornshell die Standardshell. Deshalb werde ich es lernen. Hier habe ich ein gutes Tutorial gefunden:

https://www.in.th-nuernberg.de/prof...Material/Skriptprogrammierung_v6.8_S1-244.pdf

Dann sind die nächsten Wochen ja gesichert ..... :)
 

pit234a

Well-Known Member
#8
Genau so ist es, und deshalb interessiert es mich sehr. Unter OpenBSD ist ja die Kornshell die Standardshell. Deshalb werde ich es lernen. Hier habe ich ein gutes Tutorial gefunden:

https://www.in.th-nuernberg.de/prof...Material/Skriptprogrammierung_v6.8_S1-244.pdf

Dann sind die nächsten Wochen ja gesichert ..... :)
Ich bewundere ja deinen Drang, immer wieder neue Sachen zu lernen und will dich da auch nicht abhalten.
Selbst habe ich immer wieder mal (früher deutlich häufiger) mit ash, ksh und zsh zu tun und niemals eine davon erlernt, sondern mich irgendwie durchgewurschtelt. Für meinen Minimal-Anspruch genügte dies.
Seit ich in FreeBSD die tcsh nutze, fühle ich mich damit recht wohl, erlebe aber auch häufiger, wie unterschiedlich sie zu den anderen Shells ist.
Deshalb, also aus meinen eigenen Erlebnissen heraus würde ich dir dazu raten, am ehesten die bash zu lernen.
Ganz sicher ist die bash heute die bedeutendste Shell, alleine schon weil sie Standard in GNU/Linux ist und somit eben sehr häufig eingesetzt. Alle anderen dürften eher eine Art Nischendasein pflegen.
 
R

ralli

Guest
#9
Ich bewundere ja deinen Drang, immer wieder neue Sachen zu lernen und will dich da auch nicht abhalten.
Danke!:) Nun, sicherlich kennst Du mein Alter, ich werde in Kürze 68 Jahre und bin natürlich Rentner. Und das heißt, das ich mein Dasein auch irgendwie noch sinnvoll gestalten möchte und der Tag auch ausgefüllt sein will. Und weil ich immer noch neugierig bin auf Neues, lerne ich mit Leidenschaft, die Zeit habe ich ja.

Deshalb, also aus meinen eigenen Erlebnissen heraus würde ich dir dazu raten, am ehesten die bash zu lernen.
Ganz sicher ist die bash heute die bedeutendste Shell, alleine schon weil sie Standard in GNU/Linux ist und somit eben sehr häufig eingesetzt. Alle anderen dürften eher eine Art Nischendasein pflegen.
Ganz sicher ist das so, aber OpenBSD selbst ist ja auch ein Nischenprodukt. Und damit die Kornshell ganz sicherlich auch. Aber ich habe kein Problem damit. Werde erst mal die Standard Shell aufs "Korn" nehmen. Und wenn ich das geschafft habe, mich anschließend mit der bash beschäftigen. Aber den Hinweis finde ich hilfreich, deshalb nochmals vielen Dank.
 

Yamagi

Possessed With Psi Powers
Mitarbeiter
#10
Naja, meine zugegeben etwas ketzerische Meinung zu dem Thema ist, dass sich es im Jahr 2018 nicht mehr lohnt Shell-Scripte in ihrer ganzen Widerlichkeit zu durchdringen. Shell-Script ist in sich inksonstent, hat viele scharfe Kanten, Felerbehandlung ist schwer und es niemals zu 100% portabel. Es ist gut um schnell mal etwas zusammenzukleben, dafür reicht der Kern. Zugegeben sehr kurz hier zusammengefasst: http://kirste.userpage.fu-berlin.de/chemnet/general/topics/scripts_sh.html Für alles Weitere sollte man tunlichst eine richtige Scriptsprache wie z.B. Python nehmen. Die sind unter dem Strich einfacher handzuhaben, machen einem das Leben durch ihre meist große Bibliothek und noch größere Auswahl fertiger Module wesentlich einfacher. Vor allem sind DInge wie Fehlerbehandlung wesentlich einfacher und Portabilität ist meist auch gegeben, solange man keinen Mist baut wie Pfade hartzucoden.
 

TCM

Well-Known Member
#11
Den Unterschied zwischen ${foo} und "${foo}" und warum man bei einem Test letzteres nehmen sollte, hat man aber schnell begriffen. Die Stärke der Shell ist manchmal auch, dass sie so wenig kann. Das zwingt einen, nicht zu overengineeren, denn für den Großteil der Dinge, die man mal eben schnell machen muss, reichen stdin/stdout und return codes völlig aus.
 

SierraX

Well-Known Member
#12
...
Ganz sicher ist die bash heute die bedeutendste Shell, alleine schon weil sie Standard in GNU/Linux ist und somit eben sehr häufig eingesetzt. Alle anderen dürften eher eine Art Nischendasein pflegen.
Ist die Frage wie lange noch... bei den netten features welche die zsh bietet, hat sie durchaus potential die bash zu verdrängen...
Es gibt aber auch Umstände zu beachten, die man bei skripten beachten sollte, etwa dass manche systeme wie etwa cron und at scripte unter bourne shell startet, was bei anfängern häufig dazu führt, dass diverse env variablen von ihrer Haus shell erwarten die dann irgendwie in cron nicht mehr funktionieren oder auch immer schön das vergessen der Pfade.
 

TCM

Well-Known Member
#14
Mit der Bash-Seuche hatte ich erst wieder Spaß. Tolles Linux-Script, offensichtlich unter Bash entwickelt, läuft in der initrd dann aber unter einer Minimalshell und fliegt komplett auseinander. Kann seit Monaten keiner benutzt haben. Keinen juckt's, keiner benutzt es. Richtig geil.

https://salsa.debian.org/zfsonlinux-team/zfs/blob/master/contrib/initramfs/scripts/zfs#L231

Dieses Konstrukt sucht unter der initrd-Shell und unter zsh nach einem Binary, das alle Leerzeichen und Optionen enthält, was ja völliger Quatsch ist. Funktioniert nur in der Bash so.

Also bleibt mir weg mit Bash als bedeutendste Shell. Alles, was das Teil macht, ist Amateure dazu zu ermuntern, Nicht-POSIX-Grütze zu schreiben.
 
R

ralli

Guest
#18
Nicht nur: ... wie z.B. Python... Lern Python ! :)
Du und auch @Yamagi haben mich überzeugt.:) Ansonsten gibt es hier, wen wundert es, grundsätzlich unterschiedliche Meinungen. Für manchen Anfänger und Einsteiger ein Desaster, wenn sich nicht mal die Experten einig sind!;) Aber die Basics der Kornshell will ich ebenfalls erlernen .....
 
C

CrimsonKing

Guest
#19
Auch zum Thema Python gibt es hier unterschiedliche Meinungen und über seine Nachteile, von denen die behämmerte Syntax nicht mal der größte ist, ließe sich treffend diskutieren, aber das löste das ursprüngliche Problem nicht.
 

Nonpareille

Well-Known Member
Themenstarter #20
oh, oh das wird ja jetzt richtig philosophisch. Und das nur, weil ich nicht wusste, was "<var>=$()" bewirkt.
Frage an die Mods: gibt es eine Möglichkeit, das Thema als erledigt zu markieren? Meine Frage war ja eigentlich mit der ersten Antwort schon erschöpfend beantwortet.

edit: typo
 

Yamagi

Possessed With Psi Powers
Mitarbeiter
#21
Als erledigt markieren kann man nicht. Aber: Jede Programmiersprachendiskussion auf BSDForen endet immer mit bei C und Lisp. Da diese nicht anders sein wird, beenden wir die Sache besser hier und jetzt. :)