Teil2: Programme Pfade und warum das Ausführen oft nicht klappt.

Hinweis: In dem Thema Teil2: Programme Pfade und warum das Ausführen oft nicht klappt. gibt es 1 Antwort.
  • Wenn wir ein Programm oder Script ausführen wollen, muss es der Kernel finden können.
    Geben wir in einer Konsole irgendein Kommando ein, so wird die Bash, die dieses Kommando entgegennimmt, als erstes diese Zeile parsen.
    Das Parsen ist ein Kunstwort und stammt vom Lateinischen Wort "pars", der Teil, ab.
    Die Bash zerhackt also unsere Eingabe in syntaktische hoffentlich gültige Teile.
    Dann nimmt sie alle möglichen Expansionen vor.
    Ein einsamer * wird via Globbing zu einer Dateinamensliste expandiert, ein $var Konstrukt wird mit dem Inhalt von var ersetzt.
    Sind alle diese Expansionen erledigt (und ja: es gibt noch sehr viel mehr davon), dann wird die daraus resultierende Befehlszeile an den Kernel übergeben, der sie dann letztlich auführen möchte.
    Jedenfalls so die Theorie.
    Tatsächlich fehlt hier ein ganz wesentlicher Schritt: Der Kernel hat keine Ahnung davon, wo welches Programm zu finden wäre. Das interessiert ihn nicht, das gehört nicht zu seinen Aufgaben.
    Die Bash muss also erst einmal feststellen, wo denn dieses Programm zu finden ist.
    Es gibt nun drei verschiedene Fälle, die auftreten können.
    Im Folgenden verwende ich "someCmd" als Platzhalter für jedes beliebige Programm oder Script, das ausgeführt werden kann (also lauffähig installiert irgendwo rumliegt).


    Die drei möglichen Aufrufe von "someCmd":

    Im ersten Fall, dem schlichten someCmd wird die Envrionmentvariable PATH durchsucht. Jeder Prozess hat in seiner Datenstruktur auch ein Envrionment.
    Das kann man natürlich auch aus /proc lesen: cat /proc/$$/environ Da "environ" wirklich eine Datei ist, nehmen wir "cat" um sie anzeigen zu lassen (diese Datei auf die Standardausgabe ==Bildschirm concatenieren zu lassen.)
    Da der Kernel intern immer mit der binären Null als Trenner arbeitet, erhalten wir damit ziemlich unlesbaren Zeichensalat, den wir aber mit dem Filter translate leicht lesbar machen können, indem wir die binären Nullen mit Newlinezeichen ersetzen lassen: cat /proc/$$/environ | tr '\0' '\n'
    Et voila: Fast die exakt gleiche Ausgabe, wie der Befehl env, der auch (fast) alle Environmentvariablen ausgeben kann. (die zweite Aufgabe von env ist es, nach Programmen zu suchen).
    Wir können die Variable PATH natürlich sehr viel einfacher ausgeben lassen, ohne lange zu suchen: echo $PATH.
    Bei der einfachen Form eines Aufrufes MUSS das Programm oder Script in einen dieser Verzeichnisse gefunden werden, oder es gibt eine Fehlermeldung.


    Was auch nicht so wirklich vollständig wahr ist. Man probiere einfach als normaler User das hier:

    Bash
    looser@computer:~> hwinfo
    Absolute path to 'hwinfo' is '/usr/sbin/hwinfo', so running it may require superuser privileges (eg. root).


    Das Programm, findet sich tatsächlich in dem Verzeichnis /usr/sbin/. Und würden wir es einfach mit absolutem Pfad, also so: /usr/sbin/hwinfo aufrufen, würde es auch einfach laufen und uns sogar die gewünschte Information ausgeben. Das ist aber eine Erweiterung und nicht die reine Linuxlehre. Findet die Bash das Programm in einem der sbin (SytemBINaries) Verzeichnisse, so wird freundlicherweise der Hinweis ausgeben: "Bua, wos machst? Des Brogramm is doch in /sbin!!! Junge, da brauchste wohl root- Rechte!"
    Es ist aber so, dass viele Systemprogramme, die eigentlich root vorbehalten sind, sehr wohl vom normalen User aufgerufen werden können. Es lässt sich halt mit den normalen Userrechten nichts ändern, aber viele geben wenigstens Informationen aus. Einfach fleißig ausprobieren. Das ist völlig legitim.


    Und wir haben jetzt gesehen, dass ein Aufrun mit absolutem Pfad immer funktioniert.


    Bleibt noch der relative Pfad.
    Ein absoluter Pfad beginnt immer im Wurzelverzeichnis ganz oben, und das ist nun mal /
    Also beginnt ein absoluter Pfad IMMER mit einem Slash.


    Ein realtiver Pfad gilt IMMER NUR vom aktuellen cwd aus. Dabei stehen zwei Punkte .. für "ein Verzeichnis höher" und ein Punkt . für das aktuelle Verzeichnis. Wir nehmen an, das wir im absolut angegebenen Verzeichnis /home/looser/otherDir ein Script names someCmd liegen haben.
    Im Falle unserer beiden relativen Pfadaufrufe:


    ./someCmd
    ../looser/otherDir/someCmd würde der erste Aufruf nur klappen, wenn wir als cwd eben in /home/looser/otherDir stehen würden. Wir sagen ja explizit mit unserem relativen Aufruf: Im aktuellen Verzeichnis ./ und dort das Programm someCmd.
    Beim zweiten relativen Aufruf können wir in einem beliebigen Unterverzeichnis von /home stehen (also unser cwd ist irgendein Unterverzeichnis von /home).
    Die ersten zwei Punkte in diesem Aufruf sagen, ein Verzeichnis höher, also /home und dann dort das Unterverzeichnis looser/otherDir und dort das....
    Also letztlich genau das gleiche. Und es funktioniert natürlich ebenso, wenn wir schon in /home/looser stehen. Wenn auch von da aus umständlich erst eines höher und dann wieder runter.


    Damit sollte nun auch klar sein, dass man oft ./neuHerunterGeladenesInstallationsScript lesen kann: Es liegt irgendwo, und wird von dort aufgerufen. Man muss also entweder den absoluten Aufruf, oder den kürzeren relativen mit dem ./ vornedran verwenden.
    Hassadeure erweitern die Pfadvariable einfach um :. Der Doppelpunkt ist das Trennzeichen zwischen den einzelnen Pfadangaben und der Punkt steht, wie wir jetzt ja wissen, für das aktuelle Verzeichnis. Will man das, wovon aus Sicherheitsgründen abzuraten ist, so kann man das mit export PATH="$PATH:." in seinem Home der Datei .bashrc hinzufügen. Ab da kann man, egal wo man steht, jedes Programm aufrufen, das dort liegt, weil es eben über die PATH - Suche der Shell gefunden werden kann.


    Wenn ihr nun irgendwelche Scripte schreibt, oder gar Daemons konfiguriert, oder Desktopfiles erstellt, ist es gute Sitte und macht garantiert weniger Kopfschmerzen IMMER absoulte Pfade zu verwenden. Das klappt dann.
    Das ist insbesondere wichtig für Programme, die in anderem Kontext mit anderen Home (oder keinem ) ausgeführt werden.
    cron wäre das das Paradebeispiel. Ein Programm oder Scripte, die von cron periodisch ausgeführt werden sollen laufen NUR, wenn man für JEDEN Befehl einen absoluten Aufruf verwendet. Solche Programmläufe haben nicht einmal ein Terminal, weshalb auch alle möglichen Ausgaben dieser Programme abgefangen werden sollen.


    Die Geschichte ist noch lange nicht am Ende.
    Was, wenn das Programm gar nicht im Dateisystem vorhanden ist?
    Ein cat script | ssh someUser:AtSomeOtherHost würde das Script script, das nur lokal vorhanden ist auf dem Rechner AtSomeOtherHost ausführen.
    Da beginnen die Dinge dann etwas komplizierter zu werden.
    Muss aber auf unserem Niveau noch nicht interessieren. Und genuch gebabbelt hab ich jetz auch.


    Wenn euch irgendwelche Leute erzählen, dass man keine absoluten Pfade brauchen würde, lächelt und ignoriert sie.
    Sie wissen es (noch) nicht besser.

  • Da das hier wieder zu einem Shitstorm ausartet ... Geschlossen und Beiträge mit keinem relevanten Bezug zum Thema gelöscht.