/ usr / bin / env: php: Keine solche Datei oder kein solches Verzeichnis

9

Ich möchte das .sh-Skript für die Bereitstellung meiner App verwenden. Dieses Skript befindet sich auf meinem Heimserver (Ubuntu 15.10 Server) und ist als ausführbar markiert. Der Zugriff auf dieses Skript erfolgt über ssh. Mit diesem Tutorial habe ich die ssh-Anmeldung eingerichtet, mit der dieses Skript ausgeführt wird. Im Grunde rufe ich einfach auf ssh [email protected] someArgumentsund es führt mein Skript mit someArgumentsals Parameter aus. Der Benutzer deployerhat uid = 0, also ist es im Grunde root(dies wird in Zukunft geändert, ich habe es nur eingestellt, um Berechtigungsprobleme zu beseitigen, bis es gut funktioniert).

Und hier wird es schwierig. Das Skript meldet /usr/bin/env: php: No such file or directoryauf Befehl /bin/composer install(mit Composer ). Die Dinge sind seltsamer, je mehr ich auf dieses Skript schaue. Vor dieser Zeile steht auch /bin/composer self-updateund /bin/composer -V, das korrekt ausgeführt wird und die korrekte Ausgabe anzeigt.

Ich habe folgende Dinge überprüft:

  • /usr/bin/env php -vzeigt die korrekte PHP-Version an (wie /usr/bin/php -v)
  • whereis php Anzeigen php: /usr/bin/php /usr/local/bin/php /usr/share/man/man1/php.1.gz
  • php5-cli Paket ist installiert und neueste Version
  • $PATH enthält /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
  • which env Anzeigen /usr/bin/env

Ich habe auch folgende Dinge versucht:

  • Das Skript direkt wie bash deploy.shunter root ausführen (da es mit diesem Benutzer identisch ist) - funktioniert einwandfrei ohne Fehler
  • Fehlerhafte Befehle direkt ausführen - auch perfekt ohne Fehler

Dies scheint mir also ein sehr spezifischer Fall zu sein, warum dieser Befehl nicht funktioniert. Ich habe 12 Stunden mit dem Debuggen verbracht und habe hier keine Ideen mehr.

PS: Ein ähnlicher Fehler ( /usr/bin/env: node: No such file or directory) tritt auf, wenn bower install(mit Bower ), aber nicht beim Ausführen npm install(mit NPM ).

Tomáš Blatný
quelle
Laufen sh deploystatt bash deploy(vielleicht etwas Bashismus). Wie haben Sie die " folgenden Dinge " überprüft ? Ich empfehle, sie im Skript zu überprüfen, damit Sie eventuelle Überschreibungen und Bereinigungen von Envs feststellen können.
Giacomo Catenazzi
zu " folgenden Dingen ": Ich habe sie hinzugefügt, um das Skript "deploy.sh" zu starten, und sie geben diese Dinge aus, die ich in Frage gestellt habe. Die gleiche Ausgabe ist, wenn ich sie alleine laufen lasse.
Tomáš Blatný
sh deployund bash deploybeide geben die gleichen Ergebnisse
Tomáš Blatný
Zeigen Sie diese Zeile bitte hier. Ich empfehle Ihnen, Ihren PHP- Befehl in dieser Zeile Ihres Skripts durch eine Ausgabe in eine Datei zu ersetzen , um Umgebungsvariablen im Moment des Aufrufs von / usr / bin / env zu untersuchen:/usr/bin/env > environment.txt
Oleg Bolden

Antworten:

6

Stellen Sie sicher, dass Zeilenenden und / oder unsichtbare Leerzeichen das Problem nicht verursachen.

Entfernen Sie die Leerzeichen in der ersten Zeile des Skripts und fügen Sie neue ein. Achten Sie dabei darauf, dass Sie beim Drücken der Leertaste nicht die STRG-Taste gedrückt halten.

Stellen Sie außerdem sicher, dass Sie keine DOS-Zeilenenden (CR + LF) haben. Weitere Informationen finden Sie unter /programming/82726/convert-dos-line-endings-to-linux-line-endings-in-vim .

neuhaus
quelle
Ich verwende eine IDE, die nur CR + LF automatisch in LF überprüft (und konvertiert), Stücklisten entfernt und sich um weiße Zeichen kümmert, aber ich habe es doppelt überprüft und es scheint in Ordnung zu sein (funktioniert aber immer noch nicht). Trotzdem danke
Tomáš Blatný
4

Einfachster Weg .... Ändern Sie die Shell des Benutzers als Skript.

/ etc / passwd

Before:
deploy:x:0:0:,,,:/root:/bin/bash

After:
deploy:x:0:0:,,,:/root:/scripts/deploy.sh

Beispielskript (stellen Sie sicher, dass das Ausführungsbit auf chmod + x gesetzt ist)

/scripts/deploy.sh

#!/bin/bash 
PATH=$PATH:/moo etc...
moo.sh

Stichprobe Funktioniert immer! Sie sollten sogar in der Lage sein, das Skript zur Fehlerbehebung / zum Debuggen von Env-Variablen zu verwenden, von denen Sie glauben, dass sie nicht gesetzt sind usw. Auch die an ssh übergebenen Verarbeitungsargumente funktionieren.

Hinweis: Es wird empfohlen, die Pfade für Skripte, ausführbare Dateien usw. immer VOLLSTÄNDIG ZU QUALIFIZIEREN. Oben ist nur ein Beispiel aufgeführt, mit dem der Standardpfad so festgelegt werden kann, dass er moo.sh im Ordner moo aufruft.

Das war einfach .. Danke fürs posten ..

Referenz: / etc / passwd Format

NotAdmin Dave
quelle
Schöne Antwort, aber ich benutze den Benutzer eigentlich nie direkt auf dem Server, sondern immer sshauf dem Server, und nach dem Lane-In authorized_keyswird das Skript aufgerufen und die Verbindung beendet. Wie soll ich Änderungen vornehmen authorized_keys, damit dies funktioniert?
Tomáš Blatný
Es sollte genauso funktionieren. Sie würden sich über einen Schlüssel authentifizieren. Solange die Shell auf das Skript für das betreffende Remote-Konto in der Datei / etc / passwd des Remote-Servers eingestellt ist, wird das Skript ausgeführt. Ich werde in Kürze einen Screenshot zu meinem Beitrag hinzufügen.
NotAdmin Dave
1
@ Dave kann nicht auf Ihr Buch warten
Burgi
Vielen Dank für Ihre Antwort, es hat mein Problem nicht gelöst, war aber für mich das interessanteste und tatsächlich gelöste andere Problem, das ich hatte. Gab Ihnen das Kopfgeld, nochmals vielen Dank
Tomáš Blatný
4

Der envBefehl durchsucht einen Benutzer $PATHnach der ersten ausführbaren Datei mit dem angegebenen Namen. So /usr/bin/env phpwird für eine ausführbare Datei mit dem Namen suchen phpin einem der Verzeichnisse in der $PATHder Benutzer es läuft.

In Ihrem Fall liegt das mit ziemlicher Sicherheit daran, dass Sie beim Ausführen eines Befehls sshkeine vollständige Shell starten und die Initialisierungsdateien Ihrer Shell nicht lesen. Sie können dies überprüfen, indem Sie diesen Befehl ausführen (beachten Sie die einfachen Anführungszeichen):

ssh deployer@XXX.com 'echo $PATH'

Und vergleichen Sie die Ausgabe mit dem, was Sie erhalten, wenn Sie ssh [email protected]und dann ausführen echo $PATH. Auf meinem System. beispielsweise:

$ echo $PATH
/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:

$ ssh localhost 'echo $PATH'
/usr/bin:/bin:/usr/sbin:/sbin

Daher ist das $PATH, auf das Ihr Skript beim Ausführen Zugriff hat, ssh [email protected]nicht dasselbe wie beim Anmelden, um es zu testen.

In jedem Fall besteht die einfache Lösung darin, stattdessen den vollständigen Pfad zum Interpreter zu verwenden env. Beide envund vollständige Pfade haben ihre Vor- und Nachteile, aber in diesem Fall ist der Pfad sicherer:

#!/usr/bin/php
Terdon
quelle
ITYM " beachten Sie die einfachen Anführungszeichen" nicht " nicht ".
Dave_thompson_085
@ dave_thompson_085 in der Tat habe ich getan, danke.
Terdon
Ich verwende tatsächlich überall vollständige Pfade, wie ich in meiner Frage erwähnt habe. Der Fehler wird im composer install Befehl gemeldet , den ich offensichtlich nicht ändern kann. $PATHIst auch in Ordnung, wie ich auch in meiner Frage erwähnt habe, habe ich alle Dinge überprüft, indem ich sie in das Skript eingefügt und per SSH-Login remote ausgeführt habe. Ich kann das auch nicht überprüfen, ssh [email protected] 'echo $PATH'wie Sie angegeben haben, da mein SSH-Login nur auf ein Skript beschränkt ist, aber ich habe es jedoch überprüft, als ich $ PATH zu diesem Skript hinzugefügt habe (siehe oben). Wie auch immer, danke für Ihre Antwort und akzeptiere + 1 für die Erklärung der envSache
Tomáš Blatný
@ TomášBlatný Nun, Sie verwenden irgendwo env, oder Sie würden diesen Fehler nicht sehen. Ich kenne keinen Komponisten, aber Sie müssen wahrscheinlich die ausführbare PHP-Datei kopieren oder mit einem Verzeichnis in ihrem Pfad verknüpfen. Diese Art von Dingen ist schwer zu debuggen, da es so viele Dinge gibt, die voneinander abhängen.
Terdon
Das stimmt, envheißt eigentlich Inside Composer. Dies löst jedoch nicht das Problem, warum einige Komponistenaufrufe bestehen und andere nicht. Ich werde dies jedoch weiter untersuchen, indem ich mir den Code anschaue. Vielen Dank für Ihre Zeit
Tomáš Blatný
2

Ist es möglich, dass bashein Reset auf die Hash-Tabelle erforderlich ist?

In diesem Fall können Sie versuchen, hash -rirgendwo in Ihrem Skript etwas hinzuzufügen , wodurch die Shell gezwungen wird, $PATHerneut zu suchen , anstatt sich auf (möglicherweise veraltete) Informationen aus der Hash-Tabelle zu verlassen.

Bei Bedarf hashkann die Shell mithilfe der -pOption auch Pfade zu ausführbaren Dateien speichern, die an nicht standardmäßigen Speicherorten installiert sind , oder Pfade mit der -dOption vergessen .

Quellen:

https://unix.stackexchange.com/a/86017/121251
https://stackoverflow.com/a/22543353/2146843

fliegender Finger
quelle
Dies hat das Problem für mich nicht gelöst, aber es ist ein gutes Wissen, also habe ich Ihnen eine +1
Tomáš Blatný
1

Sieht so aus, als müssten Sie Ihrem Pfad PHP hinzufügen. Versuchen:

vim ~/.bashrc
PATH=$PATH:/usr/local/bin/php
export PATH

Vielleicht möchten Sie auch überprüfen, wo Ihr PHP lebt, um sicherzustellen, dass der Pfad dort korrekt ist. Versuchen:

which php
Jeramy
quelle
Nun, das ist nicht das Problem, da die php -vkorrekte PHP-Version und die composer --versionComposer-Version ausgegeben werden. Wie gesagt, das Problem liegt nur in einem Befehl.
Tomáš Blatný
1

Es ist klar, dass Sie ein Pfadproblem haben, da Ihr Bereitstellungsskript bei einer normalen SSH-Anmeldung keine Dinge finden kann, die sich definitiv auf dem Pfad befinden.

Um zu bestätigen, dass Sie ein PATH-Problem haben, müssen Sie zunächst Ihr Bereitstellungsskript aktualisieren, um die Ausgabe von envoder zumindest zu protokollieren echo $PATH. Ich vermute, dass die Art und Weise, wie Ihr Bereitstellungsskript aufgerufen wird, $ PATH nicht wie erwartet festgelegt ist. Diese Debug-Ausgabe bestätigt / leugnet meine Theorie.

Ich habe mir das Tutorial angesehen, dem Sie gefolgt sind. Sie sollten wahrscheinlich bei update sicherstellen , dass die command=sein , command="/bin/sh /path/to/your/script..."wenn Sie nicht bereits haben , um sicherzustellen , dass Ihr Skript durch die rechte Schale ausgeführt wird.

Wenn Sie ein PATH-Problem haben, besteht eine schnelle / schmutzige Lösung darin, PATH zu Beginn Ihres Bereitstellungsskripts explizit festzulegen.

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"

Detaillierte Erklärung und weitere Optionen ...

Unter Linux erben Befehle, wenn sie ausgeführt werden, die Umgebung ihres übergeordneten Prozesses.

Wenn Sie sich als normaler Benutzer über SSH anmelden, kann Folgendes passieren (z. B. Ausführen von / etc / bashrc / etc / profile ~ / .bash_profile ~ / .bashrc usw.). Zu diesem Zeitpunkt haben Sie möglicherweise die Umgebung Ihres Prozesses aktualisiert, indem Sie Dinge wie export PATH="$PATH:~/mybin"in diesen Skripten ausgeführt haben. Jetzt erben alle zukünftigen Prozesse, die Sie ausführen, Ihre aktuelle Umgebung.

Das Ausführen eines Befehls anstelle einer Anmeldeshell bedeutet, dass der Befehl vom ssh-Daemon ausgeführt wird und die Umgebung des ssh-Daemon-Prozesses erbt. Dies unterscheidet sich wahrscheinlich von Ihrer Umgebung als angemeldeter Benutzer.

Die Manpage für autorisierte Schlüssel behandelt, was nach der Authentifizierung passiert. In Bezug auf die Umwelt:

  1. Liest die Datei ~ / .ssh / environment, falls vorhanden, und Benutzer dürfen ihre Umgebung ändern. Siehe die Option PermitUserEnvironment in sshd_config (5).

Der geeignete Ort zum Konfigurieren der Umgebung für den Prozess befindet sich also im ~/.ssh/environmentAusgangsverzeichnis ~des Benutzers, der zum Ausführen des Befehls authentifiziert ist. Sie müssen auch Ihre sshd_config überprüfen, um sicherzustellen, dass PermitUserEnvironment zulässig ist.

~/.ssh/environment Das Format ist natürlich auch in der Manpage angegeben.

         This file is read into the environment at login (if it exists).
         It can only contain empty lines, comment lines (that start with
         '#'), and assignment lines of the form name=value.  The file
         should be writable only by the user; it need not be readable by
         directory becomes accessible.  This file should be writable only
         by the user, and need not be readable by anyone else.

Eine alternative Möglichkeit, die Umgebung ohne Verwendung der oben genannten Methode anzugeben, besteht darin, die environment="NAME=value"Option in der Datei "authorized_keys" zu verwenden. Weitere Informationen finden Sie in der Manpage, die ich oben verlinkt habe.

mattpr
quelle
In Bezug auf Without knowing exactly how you have setup your deploy script to run: In meiner Frage am Anfang gibt es einen Link, wie ich es eingerichtet habe (mit ~/.ssh/authorized_keys. Danke für den Tipp mit dem Aktualisierungsbefehl, ich habe es versucht, aber leider ohne Unterschied. Ich werde dies jedoch weiter untersuchen und verschiedene Shells ausprobieren Bitte akzeptieren Sie eine +1 für diese Idee.
Tomáš Blatný
Haben Sie versucht, Ihr Bereitstellungsskript zu aktualisieren, um den aktuellen $ PATH auszudrucken? Könnten Sie das Ergebnis veröffentlichen? Wenn es nicht Ihren Erwartungen entspricht, können Sie einfach versuchen, den Pfad explizit festzulegen, wie ich zu Beginn Ihres Bereitstellungsskripts vorgeschlagen habe.
Mattpr