/ bin / sh: pushd: non trovato


99

Sto facendo quanto segue all'interno di un file make

pushd %dir_name%

e ottengo il seguente errore

/bin/sh : pushd : not found

Qualcuno può dirmi perché viene visualizzato questo errore? Ho controllato la mia variabile $ PATH e contiene / bin quindi non penso che questo stia causando un problema.


Non si lamenta di merda, si lamenta che non riesce a trovare pushd. È pushd nel tuo $PATH?
Konerak

7
Konerak: pushd non ha senso essere in path, è un bash builtin. Il problema è un bash builtin, non uno shell POSIX.
Jan Hudec

Perché hai modificato il codice?
Jan Hudec

1
Molto probabilmente la tua distribuzione ha spostato / bin / sh in / bin / ash invece che / bin / bash. A meno che tu non costringa specificamente il tuo Make a usare bash, userà qualunque sia / bin / sh.
stsquad

Lo stesso problema si verificherebbe anche nello script di shell se non fosse eseguito da bash.
Vladimir Kroz

Risposte:


113

pushdè un bashmiglioramento della Bourne Shell specificata da POSIX. pushdnon può essere facilmente implementato come comando, perché la directory di lavoro corrente è una caratteristica di un processo che non può essere modificata dai processi figli. (Un pushdcomando ipotetico potrebbe eseguire la chdir(2)chiamata e quindi avviare una nuova shell, ma ... non sarebbe molto utilizzabile.) pushdÈ un builtin di shell, proprio come cd.

Quindi, cambia lo script per iniziare #!/bin/basho memorizza la directory di lavoro corrente in una variabile, fai il tuo lavoro, quindi torna indietro. Dipende se vuoi uno script di shell che funzioni su sistemi molto ridotti (ad esempio, un server di compilazione Debian) o se stai bene richiedendo sempre bash.


17
OP dice che è gestito da make. Quindi sarebbe l'impostazione SHELL = /bin/bashpiuttosto che iniziare lo script con #!/bin/bash.
Jan Hudec

@Jan Hudec, ah! Buona pesca. Grazie.
sarnold

Ma l'impostazione SHELL non funzionerà in questo caso, vedi test1nella mia risposta, stackoverflow.com/questions/5193048/bin-sh-pushd-not-found/… .
hlovdal

1
@hlovdal: No, in effetti non sarà abbastanza.
Jan Hudec

1
Assicurati che #!/bin/bashsia la prima riga del file.
Michael Cole


18

Una soluzione alternativa per questo sarebbe avere una variabile per ottenere la directory di lavoro corrente. Quindi puoi uscire da esso per fare qualsiasi cosa, quindi quando ne hai bisogno, puoi tornare indietro.

cioè

oldpath = `pwd`
# fai qualunque cosa faccia il tuo script
...
...
...
# torna alla directory che volevi pushd
cd $ oldpath

6
Puoi anche cdentrare nella directory che desideri e in seguito farlo cd -, non è necessario utilizzare quella $oldpathvariabile se non la utilizzerai in cdmezzo. La cosa interessante pushdè che ogni volta che lo usi stai inserendo una directory in uno stack, e successivamente puoi tornare all'ultima usando popd, quindi ha senso usarlo quando stai andando in più di una directory e vuoi un modo sicuro per tornare indietro.
Enrico

1
Se è solo un oneliner, potrebbe funzionare anche quanto segue(cd /new_path ; command )
barney765

10

Questo perché pushd è una funzione incorporata in bash. Quindi non è correlato alla variabile PATH e inoltre non è supportato da / bin / sh (che è usato di default da make. Puoi cambiarlo impostando SHELL (sebbene non funzionerà direttamente (test1)).

Puoi invece eseguire tutti i comandi tramite bash -c "...". In questo modo i comandi, incluso pushd / popd, verranno eseguiti in un ambiente 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;"

Quando si esegue make test1 e make test2, dà quanto segue:

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>

Per test1, anche se bash viene utilizzato come shell, ogni riga di comando nella regola viene eseguita da sola, quindi il comando pushd viene eseguito in una shell diversa da popd.


1
@Jan Hudec, penso tcsh(e forse csh?) > $ tcsh haig:/> exit $ csh haig:/> exit $
Terminare il

Il mio lo fa :) In realtà la mia PS1 lo è, (\u) \h:\w>ma ora l'ho ridotta a una stringa generica per la risposta. Anche il prompt in DOS termina con >( $P$GIIRC), e questo mi piace.
hlovdal

Impostare SHELL con: = non con =
cup

L'impostazione "SHELL = / bin / bash" funziona bene per me, non sono sicuro di come hai fatto a farlo non funzionare.
Isaac Freeman

4

La tua shell (/ bin / sh) sta cercando di trovare "pushd". Ma non riesce a trovarlo perché 'pushd', 'popd' e altri comandi del genere sono compilati in bash.

Avvia il tuo script usando Bash (/ bin / bash) invece di Sh come stai facendo ora, e funzionerà



2

Sintetizzando dalle altre risposte: pushdè specifico per bash e stai usando un'altra shell POSIX. Esiste una semplice soluzione alternativa per utilizzare una shell separata per la parte che richiede una directory diversa, quindi prova a cambiarla in:

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

(Ho sostituito il percorso lungo con un'espansione variabile. Probabilmente è uno nel makefile e si espande chiaramente nella directory corrente).

Dato che lo stai eseguendo da make, probabilmente sostituirei anche il test con una regola make. Appena

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

(abbandonato il prefisso della directory corrente; stavi usando comunque il percorso relativo in alcuni punti) E poi fai semplicemente dipendere la regola gen/SvcGenLog. Sarebbe un po 'più leggibile e si può rendere dipendono dal genscript/genmakefile.pltroppo, in modo che il Makefilein genverrà rigenerato se si modifica lo script. Ovviamente se qualcos'altro influisce sul contenuto del Makefile, puoi far dipendere la regola anche da quello.


2

Notare che ogni riga eseguita da un file make viene eseguita comunque nella propria shell. Se cambi directory, non influirà sulle righe successive. Quindi probabilmente hai poco uso di pushd e popd, il tuo problema è più l'opposto, quello di far sì che la directory rimanga modificata per tutto il tempo che ti serve!


1

Esegui "apt install bash" Installerà tutto ciò di cui hai bisogno e il comando funzionerà


1

ecco un metodo da indicare

sh -> bash

eseguire questo comando sul terminale

sudo dpkg-reconfigure dash

Dopo questo dovresti vedere

ls -l /bin/sh

punta a / bin / bash (e non a / bin / dash)

Riferimento


0

Questo dovrebbe fare il trucco:

( cd dirname ; pwd ); pwd

Le parentesi iniziano una nuova shell figlio, quindi la cddirectory cambia solo all'interno del figlio e qualsiasi comando dopo di essa all'interno delle parentesi verrà eseguito in quella cartella. Una volta usciti dalle parentesi, tornerai dov'eri prima ..

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.