Was ist der Unterschied zwischen ./ und sh, um ein Skript auszuführen?

71

Ich habe ein einfaches Skript geschrieben. Wenn ich laufe sh <myscriptname.sh>, erhalte ich die richtige Ausgabe, aber wenn ich laufe ./<myscriptname.sh>, erhalte ich eine Fehlermeldung.

Was ist der Unterschied zwischen wann shund ./?

mr_eclair
quelle
15
Anstatt nur "Ich erhalte einen Fehler" zu sagen, wäre es hilfreich, wenn Sie den Fehler einfügen.
SpashHit

Antworten:

67

Wenn Sie ein Skript ausführen, indem Sie den Dateinamen an das Skriptinterpreterprogramm übergeben, führen Sie das Interpreterprogramm mit dem Skript als übergebenen Argument aus. Dies würde beispielsweise so aussehen wie der Prozess 'sh' mit dem Argument 'filename.sh'. Der shInterpreter öffnet die Datei.

Wenn Sie andererseits das Skript selbst ausführen, ruft das System das angegebene Interpreterprogramm auf und gibt den Skriptinhalt ein. In diesem Fall sieht der Prozess wie 'filename.sh' ohne Argumente aus.

Sie sollten sicherstellen, dass Sie eine Knalllinie haben:

#!/bin/bash
# bash script here

Eine Bang-Zeile ist die allererste Zeile im Skript und beginnt mit denselben zwei Zeichen #!. Diese werden vom System gelesen, wenn es versucht, das Skript auszuführen, und das System übergibt das Skript unmittelbar danach an das Programm. Beachten Sie, dass diese Zeile nichts mit bash zu tun hat und für Python und Perl genauso gut funktioniert, auch wenn sie sehr unterschiedliche Sprachen sind. Sie würden #!/usr/bin/pythonzum Beispiel verwenden und dann mit Python-Code folgen.

Stellen Sie sicher, dass Sie die Ausführungsberechtigungen festgelegt haben, nachdem Sie Ihr Skript erstellt haben:

chmod a+x filename.sh

Dann können Sie das Skript als eigenen Prozess ausführen:

./filename.sh

Oder legen Sie die Datei an einem bekannten Ort mit einem schönen Programmnamen ab, /usr/sbinund führen Sie sie von überall aus:

sudo cp filename.sh /usr/sbin/program-name
program-name

Und dies ist wirklich der praktische Vorteil der Verwendung der Bang-Line mit den richtigen Berechtigungen - es geht nur um die Bereitstellung . Es ist sehr schwierig, Benutzer zum Ausführen eines Skripts zu bewegen, wenn sie sich merken müssen, mit welchem ​​Programm das Skript ausgeführt werden soll. Denken Sie daran, dem Skript bei jeder Ausführung einen vollständigen Pfad zuzuweisen. Wenn Sie es beispielsweise einfügen /usr/local/binund ausführbar machen, können Sie den Leuten, die versuchen, Ihr Skript zu verwenden, sehr viel Kummer ersparen. Diese Programme stehen dann allen Benutzern auf Ihrem Computer zur Verfügung.

Es ist auch gut für die Identifizierung. Wenn Sie in das gehen topProgramm, ohne den Knall Linie ein Skript ausführen , müssen Sie einfach den Namen des Interpreten dh bash, perloder python. Wenn jedoch ein Skript mit den richtigen Berechtigungen ausgeführt wird, wird der Name des Skripts angezeigt.

Hinweis: Wenn Sie ein Skript verteilen möchten, auf das jeder zugreifen kann, erstellen Sie bitte eine Manpage und ein Deb-Paket, um es zu installieren. Wir müssen die Anzahl der zufälligen Skripte online reduzieren und die Anzahl der Debs erhöhen, die deinstalliert werden können.

Martin Owens -doctormo-
quelle
1
Sie können auch einen persönlichen Ordner "bin" verwenden: Erstellen Sie einen Ordner "bin", und melden Sie sich ab und wieder an. Anschließend sollten Sie in diesem Ordner alle Skripts ohne sh oder ./ ausführen können.
Papukaija
Natürlich, aber das Hinzufügen Ihres Home-Ordners zu Ihrem PATH bereitet ein bisschen Kopfzerbrechen. Besser Dinge installieren lassen. Es gab zwar einige Überlegungen, dem Pfad standardmäßig ~ / .local / bin hinzuzufügen, um die Installation von Paketen durch lokale Benutzer zu ermöglichen.
Martin Owens -doctormo-
Beachten Sie, dass der Standardinterpreter bashnicht ist sh.
Nathan Osman
1
Fügen Sie keine Erweiterungen zu Skripten hinzu, insbesondere nicht, wenn Sie sie einfügen PATH.
Geirha
1
/usr/local/binist wahrscheinlich besser als /usr/sbin- es zeigt an, dass das Programm lokal auf diesem Computer ist, anstatt Teil der Distribution zu sein.
Glenn Jackman
41

Die kurze Version:

  • shist der Befehlszeileninterpreter (Bindestrich).
    Beim Ausführen sh my_scriptinterpretiert dash das Skript.

  • ./versucht anhand der ersten Zeile herauszufinden, welcher Interpreter verwendet werden soll. ZB #!/bin/bashoder sogar #!/bin/ruby(im Gegensatz zum Laufen ruby my_script).

Stefano Palazzo
quelle
7
Es ist nicht wirklich ./was etwas findet, es ist die Systemausführungsmethode, die die ersten zwei Bytes der Datei betrachtet.
Martin Owens -doctormo-
9
Absolut. Hier ist eine sehr lange Erklärung von allem. Ich bin pragmatisch :)
Stefano Palazzo
Wenn Sie shsha-bang verwenden und die Datei enthält, bedeutet dies, dass sha-bang ignoriert wird, oder öffnet es die Shell, in der sich auch shLinks befinden, und dann vielleicht eine andere Shell, oder was macht es :)?
Ini
5

Der Unterschied ist,

  • Mit führen shSie ein Programm aus, das die Zeilen in Ihrem Skript so interpretiert, als hätten Sie sie über die interaktive Eingabeaufforderung des Terminals eingegeben.

  • Wenn ./Sie eine Verknüpfung erstellen, gehen Sie davon aus, dass sich das Skript genau hier in dem aktuellen Verzeichnis befindet, in dem Sie sich befinden, UND dass es ausführbar sein wird (zum Beispiel, weil Sie es ausgestellt haben chmod +x myscript.sh), was Ihnen wertvolle Zeit für zukünftige Zeiten erspart :-)

meduz
quelle
3
+1, weil es die einzige ist, die genau angibt, dass die Datei ausführbar sein muss.
Mikel
2
Beachten Sie, dass mit shder Datei nicht unbedingt ausführbar sein muss.
Ini
3

Es gibt drei Hauptgründe, warum Sie möglicherweise eine Fehlermeldung erhalten:

  • die Datei ist nicht ausführbar
    Lauf chmod +x <myscriptname.sh>zu beheben , dass
  • Die Partition erlaubt nicht das Ausführen von Skripten (wird eingehängt " noexec").
    Kopieren Sie das Skript nach/usr/local/bin
  • In der #!Zeile ist ein Fehler
    aufgetreten. Vergewissern Sie sich, dass die erste Zeile #!/bin/shoder ist#!/bin/bash

Wenn Ihre erste Zeile richtig aussieht, aber immer noch nicht funktioniert, stellen Sie sicher, dass die Datei keine DOS-Zeilenenden hat.

Der Fehler würde ungefähr so ​​aussehen:

$ ./myscript.sh
bash: ./myscript.sh: /bin/bash^M: bad interpreter: No such file or directory

Sie können das Problem beheben, indem Sie ausführen dos2unix <myscriptname.sh>oder wenn Sie das nicht haben
perl -p -i -e 's/\r\n$/\n/' <myscriptname.sh>.

Mikel
quelle
0

Und die Antwort ist, dass sh der Name für eine sehr beliebte Shell ist. Aber veraltet und durch andere ersetzt. Heutzutage ist sh mit anderen auf der Maschine installierten Shells verbunden. zB habe ich dort bash geputtet. Wenn Sie eine Shell von sh aus ausführen, wird normalerweise ein Kompatibilitätsmodus mit dem ursprünglichen Shell-Verhalten ausgelöst.

Die Lösung ist also ganz einfach. Schauen Sie nach, was sich hinter dem Befehl sh befindet (ls -al / bin / sh), und geben Sie #! / Bin / whatever_you_find_there als erste Zeile ein (oder bearbeiten Sie es, wenn es so etwas in Ihrem Skript gibt).

Und alternativ könnte es einen Fehler im Skript selbst geben. Wie eine Abhängigkeit, die von sh erfüllt wird, aber kein Interpret, der tatsächlich benutzt wird.

przemo_li
quelle
0
mkdir ~/bin ; cp myscript.sh ~/bin/

echo "export PATH="$PATH:/home/$USER/bin" >> ~/.profile ; source ~/.profile ; 

Nicht /usr/sbin, das ist für unwesentliche administrative Tools /usr/local/bineine bessere Wahl, wenn Sie keine haben möchten ~/bin/, aber sudoes ist ratsam , so viel wie möglich zu vermeiden .

Joey1978
quelle
Unter Ubuntu enthält der Standardcode ~/.profilebereits Code zum Hinzufügen von ~/bin, falls vorhanden, zu PATH. In einem anderen Fall sollten Sie keine Erweiterungen für Skripte vornehmen.
Geirha
1
Ich habe auf die Datei <myscriptname.sh> verwiesen, aber was ist der Grund dafür, dass Skripten keine Erweiterungen hinzugefügt werden? Normalerweise mache ich das, weil ich mit den so sichtbaren Klartextdateien nicht versuchen kann, Binärdateien zu bearbeiten, die ich auch in ~ / bin / behalte. ( ls ~/bin/|wc -l = 428) Ich habe eine Menge Zeug da
reingesteckt
Stellen Sie sich vor, Sie schreiben ein Skript, um eine bestimmte Aufgabe zu erfüllen. Dann stellen Sie fest, dass das Schreiben dieses speziellen Skripts in Python wesentlich effizienter ist. Sie können es also in Python umschreiben. Jetzt haben Sie zwei Möglichkeiten. 1) Lassen Sie die jetzt sehr irreführende .sh-Erweiterung oder 2) benennen Sie das Skript um und suchen und ersetzen Sie alle Verwendungen des Skripts, um den neuen Namen zu verwenden. Wenn man sich die Skripte sehen in /binund /usr/binSie werden sehen , dass sie nicht Erweiterungen verwenden.
Geirha