/ bin / sh: pushd: nie znaleziono


99

Wykonuję następujące czynności wewnątrz pliku make

pushd %dir_name%

i otrzymuję następujący błąd

/bin/sh : pushd : not found

Czy ktoś może mi powiedzieć, dlaczego ten błąd się pojawia? Sprawdziłem moją zmienną $ PATH i zawiera ona / bin, więc nie sądzę, że powoduje to problem.


Nie narzeka na sh, narzeka, że ​​nie może znaleźć pushd. Czy jest wciśnięty w twoim $PATH?
Konerak

7
Konerak: pushd nie ma sensu być na ścieżce, to wbudowany bash. Problem polega na tym, że jest wbudowana bash , a nie powłoka POSIX.
Jan Hudec

Dlaczego wyedytowałeś kod?
Jan Hudec

1
Najprawdopodobniej twoja dystrybucja przeniosła / bin / sh do / bin / ash zamiast / bin / bash. O ile nie zmusisz swojego Make do używania bash, użyje tego, czym jest / bin / sh.
stsquad

Ten sam problem wystąpiłby również w skrypcie powłoki, gdyby nie był wykonywany przez bash.
Vladimir Kroz

Odpowiedzi:


113

pushdjest bashrozszerzeniem powłoki Bourne Shell określonej w standardzie POSIX. pushdnie można łatwo zaimplementować jako polecenie, ponieważ bieżący katalog roboczy jest cechą procesu, której nie można zmienić przez procesy potomne. (Hipotetyczne pushdpolecenie może wykonać chdir(2)wywołanie, a następnie uruchomić nową powłokę, ale ... nie byłoby to zbyt użyteczne.) pushdJest wbudowaną powłoką, tak jak cd.

Zatem albo zmień skrypt, aby zaczynał od, #!/bin/bashalbo zapisz bieżący katalog roboczy w zmiennej, wykonaj swoją pracę, a następnie zmień z powrotem. Zależy od tego, czy potrzebujesz skryptu powłoki, który działa na bardzo ograniczonych systemach (powiedzmy, serwer kompilacji Debiana), czy też możesz zawsze wymagać bash.


17
OP mówi, że jest produkowany od marki. Więc byłoby to ustawienie SHELL = /bin/bashzamiast uruchamiania skryptu z #!/bin/bash.
Jan Hudec

@Jan Hudec, ah! Dobry chwyt. Dzięki.
sarnold

Ale ustawienie SHELL nie zadziała w tym przypadku, zobacz test1w mojej odpowiedzi stackoverflow.com/questions/5193048/bin-sh-pushd-not-found/… .
hlovdal

1
@hlovdal: Nie, rzeczywiście to nie wystarczy.
Jan Hudec

1
Upewnij się, że #!/bin/bashjest to pierwsza linia pliku.
Michael Cole,


18

Aby obejść ten problem, zmienna powinna pobierać bieżący katalog roboczy. Następnie możesz z niego wydobyć CD, aby zrobić cokolwiek, a kiedy tego potrzebujesz, możesz z powrotem wejść.

to znaczy

oldpath = `pwd`
# rób wszystko, co robi twój skrypt
...
...
...
# wróć do katalogu, który chciałeś wysłać
cd $ oldpath

6
Możesz także przejść cddo katalogu, który chcesz, a potem zrobić cd -, nie musisz używać tej $oldpathzmiennej, jeśli nie będziesz używać cdmiędzy. Ciekawostką pushdjest to, że za każdym razem, gdy go używasz, umieszczasz katalog na stosie, a potem możesz wrócić do ostatniego, używając popd, więc sensowne jest użycie go, gdy wchodzisz do więcej niż jednego katalogu i chcesz pewna droga powrotna.
Enrico

1
Jeśli to tylko oneliner, może zadziałać również to, co następuje(cd /new_path ; command )
barney765

10

Dzieje się tak, ponieważ pushd jest funkcją wbudowaną w bash. Nie jest więc powiązany ze zmienną PATH, a także nie jest obsługiwany przez / bin / sh (który jest używany domyślnie przez make. Możesz to zmienić ustawiając SHELL (chociaż nie będzie to działać bezpośrednio (test1)).

Zamiast tego możesz uruchomić wszystkie polecenia bash -c "...". Spowoduje to, że polecenia, w tym pushd / popd, będą działać w środowisku bash (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;"

Podczas uruchamiania make test1 i make test2 daje to co następuje:

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>

W przypadku testu1, mimo że bash jest używany jako powłoka, każde polecenie / wiersz w regule jest uruchamiane samodzielnie, więc polecenie pushd jest uruchamiane w innej powłoce niż popd.


1
@Jan Hudec, myślę tcsh(a może csh?) > $ tcsh haig:/> exit $ csh haig:/> exit $
Kończą

Moje tak :) Właściwie moje PS1 jest, (\u) \h:\w>ale właśnie rozebrałem go do ogólnego ciągu znaków, aby uzyskać odpowiedź. Podpowiedź w DOS również >domyślnie kończy się na ( $P$GIIRC) i podoba mi się to.
hlovdal

Ustaw SHELL z: = nie z =
cup.

Ustawienie "SHELL = / bin / bash" działa dobrze dla mnie, nie jestem pewien, jak to sprawiło, że nie działa.
Isaac Freeman

4

Twoja powłoka (/ bin / sh) próbuje znaleźć „pushd”. Ale nie może go znaleźć, ponieważ „pushd”, „popd” i inne podobne polecenia są wbudowane w bash.

Uruchom skrypt za pomocą Bash (/ bin / bash) zamiast Sh, jak teraz robisz, i zadziała



2

Syntetyzacja z innych odpowiedzi: pushdjest specyficzna dla basha, a twój make używa innej powłoki POSIX. Istnieje proste obejście, aby użyć oddzielnej powłoki dla części, która wymaga innego katalogu, więc po prostu spróbuj zmienić ją na:

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

(Zastąpiłem długą ścieżkę rozwinięciem zmiennej. Prawdopodobnie znajduje się w pliku makefile i wyraźnie rozwija się do bieżącego katalogu).

Ponieważ uruchamiasz go z make, prawdopodobnie zastąpiłbym test również regułą make. Właśnie

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

(usunięto prefiks bieżącego katalogu; i tak w niektórych miejscach używałeś ścieżki względnej) I nie tylko uzależnij regułę od gen/SvcGenLog. Byłoby nieco bardziej czytelne i można zrobić to zależy od genscript/genmakefile.plzbyt, więc Makefilew genbędzie regenerowany jeśli zmodyfikować skrypt. Oczywiście, jeśli cokolwiek innego wpływa na zawartość Makefile, możesz uzależnić regułę również od tego.


2

Zauważ, że każda linia wykonywana przez plik make i tak jest uruchamiana we własnej powłoce. Jeśli zmienisz katalog, nie wpłynie to na kolejne wiersze. Więc prawdopodobnie nie masz pożytku z pushd i popd, twój problem jest bardziej odwrotny, niż zmiana katalogu tak długo, jak tego potrzebujesz!


1

Uruchom "apt install bash" Zainstaluje wszystko, czego potrzebujesz, a polecenie zadziała


1

oto metoda na wskazanie

sh -> bash

uruchom to polecenie na terminalu

sudo dpkg-reconfigure dash

Po tym powinieneś zobaczyć

ls -l /bin/sh

wskaż / bin / bash (a nie / bin / dash)

Odniesienie


0

To powinno załatwić sprawę:

( cd dirname ; pwd ); pwd

Nawiasy rozpoczynają nową powłokę podrzędną, a zatem cdzmienia katalog tylko w obrębie dziecka, a każde polecenie znajdujące się po nim w nawiasach zostanie uruchomione w tym folderze. Po wyjściu z nawiasów jesteś z powrotem tam, gdzie byłeś wcześniej.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.