/ bin / sh: pushd: nicht gefunden

99

Ich mache das Folgende in einer make-Datei

pushd %dir_name%

und ich bekomme folgenden Fehler

/bin/sh : pushd : not found

Kann mir bitte jemand sagen, warum dieser Fehler auftritt? Ich habe meine Variable $ PATH überprüft und sie enthält / bin, damit ich nicht glaube, dass dies ein Problem verursacht.

Pein
quelle
Es beschwert sich nicht über sh, es beschwert sich, dass es nicht finden kann pushd. Ist Pushd in deinem $PATH?
Konerak
7
Konerak: pushd macht keinen Sinn, auf dem Weg zu sein, es ist eine eingebaute Bash. Das Problem ist eine eingebaute Bash , keine POSIX-Shell.
Jan Hudec
Warum haben Sie den Code herausgeschnitten?
Jan Hudec
1
Höchstwahrscheinlich hat Ihre Distribution / bin / sh nach / bin / ash anstatt nach / bin / bash verschoben. Sofern Sie Ihr Make nicht ausdrücklich zur Verwendung von Bash zwingen, wird alles verwendet, was / bin / sh ist.
stsquad
Das gleiche Problem würde auch im Shell-Skript auftreten, wenn es NICHT von bash ausgeführt wird.
Vladimir Kroz

Antworten:

113

pushdist eine bashErweiterung der POSIX-spezifizierten Bourne Shell. pushdkann nicht einfach als Befehl implementiert werden, da das aktuelle Arbeitsverzeichnis eine Funktion eines Prozesses ist, der von untergeordneten Prozessen nicht geändert werden kann. (Ein hypothetischer pushdBefehl könnte den chdir(2)Aufruf pushdausführen und dann eine neue Shell starten, aber ... es wäre nicht sehr brauchbar.) Ist eine eingebaute Shell, genau wie cd.

Ändern Sie also entweder zunächst Ihr Skript #!/bin/bashoder speichern Sie das aktuelle Arbeitsverzeichnis in einer Variablen, erledigen Sie Ihre Arbeit und wechseln Sie dann zurück. Hängt davon ab, ob Sie ein Shell-Skript benötigen, das auf sehr reduzierten Systemen (z. B. einem Debian-Build-Server) funktioniert, oder ob Sie es immer benötigen bash.

Sarnold
quelle
17
OP sagt, es läuft von make. Es wäre also SHELL = /bin/basheher eine Einstellung als ein Skriptstart mit #!/bin/bash.
Jan Hudec
@ Jan Hudec, ah! Guter Fang. Vielen Dank.
Sarnold
Die Einstellung von SHELL funktioniert in diesem Fall jedoch nicht, siehe test1in meiner Antwort stackoverflow.com/questions/5193048/bin-sh-pushd-not-found/… .
Hlovdal
1
@hlovdal: Nein, in der Tat wird es nicht genug sein.
Jan Hudec
1
Stellen Sie sicher, dass dies #!/bin/bashdie erste Zeile der Datei ist.
Michael Cole
29

hinzufügen

SHELL: = / bin / bash

Oben in Ihrem Makefile habe ich es bei einer anderen Frage gefunden. Wie kann ich die Bash-Syntax in Makefile-Zielen verwenden?

Juan Jose Pablos
quelle
Ja Danke. Red Hats schlägt standardmäßig zu, aber auf Debian ist es wirklich sh (oder eine Implementierung davon). Das war mein Problem.
25.
18

Eine Problemumgehung hierfür wäre, dass eine Variable das aktuelle Arbeitsverzeichnis abruft. Dann können Sie eine CD herausnehmen, um alles zu tun, und wenn Sie es brauchen, können Sie wieder eine CD einlegen.

dh

oldpath = `pwd`
# Tun Sie, was auch immer Ihr Skript tut
...
...
...
# gehe zurück zu dem Verzeichnis, das du pushen wolltest
cd $ oldpath
Klassifiziert
quelle
6
Sie können auch cdin das gewünschte Verzeichnis wechseln und cd -diese $oldpathVariable anschließend nicht mehr verwenden, wenn Sie sie nicht cdzwischendurch verwenden. Das Interessante daran pushdist, dass Sie jedes Mal, wenn Sie es verwenden, ein Verzeichnis in einen Stapel verschieben und anschließend zum neuesten Verzeichnis zurückkehren können. Daher ist popdes sinnvoll, es zu verwenden, wenn Sie in mehr als ein Verzeichnis wechseln und möchten ein sicherer Weg zurück.
Enrico
1
Wenn es nur ein Oneliner ist, kann das folgende auch funktionieren(cd /new_path ; command )
barney765
10

Dies liegt daran, dass pushd eine in bash integrierte Funktion ist. Es hängt also nicht mit der PATH-Variablen zusammen und wird auch nicht von / bin / sh unterstützt (was standardmäßig von make verwendet wird. Sie können dies ändern, indem Sie SHELL einstellen (obwohl es nicht direkt funktioniert (test1)).

Sie können stattdessen alle Befehle ausführen bash -c "...". Dadurch werden die Befehle, einschließlich pushd / popd, in einer Bash-Umgebung ausgeführt (test2).

SHELL = /bin/bash

test1:
        @echo before
        @pwd
        @pushd /tmp
        @echo in /tmp
        @pwd
        @popd
        @echo after
        @pwd

test2:
        @/bin/bash -c "echo before;\
        pwd; \
        pushd /tmp; \
        echo in /tmp; \
        pwd; \
        popd; \
        echo after; \
        pwd;"

Wenn Sie make test1 und make test2 ausführen, erhalten Sie Folgendes:

prompt>make test1
before
/download/2011/03_mar
make: pushd: Command not found
make: *** [test1] Error 127
prompt>make test2
before
/download/2011/03_mar
/tmp /download/2011/03_mar
in /tmp
/tmp
/download/2011/03_mar
after
/download/2011/03_mar
prompt>

Für test1 wird, obwohl bash als Shell verwendet wird, jeder Befehl / jede Zeile in der Regel für sich ausgeführt, sodass der Befehl pushd in einer anderen Shell als popd ausgeführt wird.

hlovdal
quelle
1
@ Jan Hudec, ich denke tcsh(und vielleicht csh?) > $ tcsh haig:/> exit $ csh haig:/> exit $
Beenden
Meins tut es :) Eigentlich ist meine PS1, (\u) \h:\w>aber ich habe sie jetzt für die Antwort auf einen generischen String reduziert. Die Eingabeaufforderung unter DOS endet ebenfalls >standardmäßig mit ( $P$GIIRC), und das gefällt mir.
Hlovdal
Setze SHELL mit: = nicht mit =
Tasse
Das Setzen von "SHELL = / bin / bash" funktioniert gut für mich, nicht sicher, wie Sie es dazu gebracht haben, nicht zu funktionieren.
Isaac Freeman
4

Ihre Shell (/ bin / sh) versucht, 'pushd' zu finden. Aber es kann es nicht finden, weil 'pushd', 'popd' und andere Befehle wie dieser in bash gebaut sind.

Starten Sie Ihr Skript mit Bash (/ bin / bash) anstelle von Sh, wie Sie es jetzt tun, und es wird funktionieren

joseignaciorc
quelle
4
sudo dpkg-reconfigure dash 

Dann wählen Sie no.

user2438597
quelle
2

Die Synthese aus den anderen Antworten: pushdist bash-spezifisch und Sie verwenden eine andere POSIX-Shell. Es gibt eine einfache Problemumgehung, um eine separate Shell für das Teil zu verwenden, das ein anderes Verzeichnis benötigt. Ändern Sie es also einfach in:

test -z gen || mkdir -p gen \
 && ( cd $(CURRENT_DIRECTORY)/genscript > /dev/null \
 && perl genmakefile.pl \
 && mv Makefile ../gen/ ) \
 && echo "" > $(CURRENT_DIRECTORY)/gen/SvcGenLog

(Ich habe den langen Pfad durch eine variable Erweiterung ersetzt. Ich bin wahrscheinlich einer im Makefile und er wird eindeutig auf das aktuelle Verzeichnis erweitert.)

Da Sie es von make aus ausführen, würde ich den Test wahrscheinlich auch durch eine make-Regel ersetzen. Gerade

gen/SvcGenLog :
    mkdir -p gen
    cd genscript > /dev/null \
     && perl genmakefile.pl \
     && mv Makefile ../gen/ \
    echo "" > gen/SvcGenLog

(Das aktuelle Verzeichnispräfix wurde gelöscht. Sie haben ohnehin an einigen Stellen den relativen Pfad verwendet.) Und dann machen Sie die Regel einfach abhängig von gen/SvcGenLog. Es wäre ein bisschen besser lesbar und Sie können es auch von dem abhängig machen genscript/genmakefile.pl, so dass das MakefileIn genneu generiert wird, wenn Sie das Skript ändern. Wenn sich irgendetwas anderes auf den Inhalt von auswirkt Makefile, können Sie die Regel natürlich auch davon abhängig machen.

Jan Hudec
quelle
2

Beachten Sie, dass jede von einer make-Datei ausgeführte Zeile ohnehin in einer eigenen Shell ausgeführt wird. Wenn Sie das Verzeichnis wechseln, wirkt sich dies nicht auf nachfolgende Zeilen aus. Sie haben also wahrscheinlich wenig Verwendung für pushd und popd. Ihr Problem ist eher das Gegenteil, nämlich das Verzeichnis so lange zu ändern, wie Sie es brauchen!

Mark Baker
quelle
1

Führen Sie "apt install bash" aus. Es installiert alles, was Sie benötigen, und der Befehl funktioniert

MatanN
quelle
1

Hier ist eine Methode zu zeigen

sh -> bash

Führen Sie diesen Befehl auf dem Terminal aus

sudo dpkg-reconfigure dash

Danach sollten Sie sehen

ls -l /bin/sh

Zeigen Sie auf / bin / bash (und nicht auf / bin / dash).

Referenz

Muhammad Numan
quelle
0

Dies sollte den Trick tun:

( cd dirname ; pwd ); pwd

Die Klammern starten eine neue untergeordnete Shell, wodurch das cdVerzeichnis nur innerhalb des untergeordneten Verzeichnisses geändert wird und alle darauf folgenden Befehle in den Klammern in diesem Ordner ausgeführt werden. Sobald Sie die Klammern verlassen, sind Sie wieder da, wo Sie vorher waren.

Born2Smile
quelle