/ 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.

Pein
źródło
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.

sarnold
źródło
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,
29

Dodaj

POWŁOKA: = / bin / bash

na początku twojego pliku makefile znalazłem go w innym pytaniu. Jak mogę używać składni Bash w celach Makefile?

Juan Jose Pablos
źródło
Tak dzieki. Red Hats domyślnie bash, jednak w Debianie jest to naprawdę sh (lub jakaś jego implementacja). To był mój problem.
lzap
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
Sklasyfikowany
źródło
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.

hlovdal
źródło
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

joseignaciorc
źródło
4
sudo dpkg-reconfigure dash 

Następnie wybierz no.

user2438597
źródło
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.

Jan Hudec
źródło
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!

Mark Baker
źródło
1

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

MatanN
źródło
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

Muhammad Numan
źródło
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.

Born2Smile
źródło