/ bin / sh: pushd: introuvable

99

Je fais ce qui suit dans un fichier make

pushd %dir_name%

et j'obtiens l'erreur suivante

/bin/sh : pushd : not found

Quelqu'un peut-il me dire pourquoi cette erreur apparaît? J'ai vérifié ma variable $ PATH et elle contient / bin donc je ne pense pas que cela pose un problème.

Pein
la source
Il ne se plaint pas de sh, il se plaint qu'il ne trouve pas pushd. Est-ce que pushd est dans votre $PATH?
Konerak
7
Konerak: pushd n'a aucun sens d'être sur le chemin, c'est un bash intégré. Le problème étant un bash intégré, pas un shell POSIX.
Jan Hudec
Pourquoi avez-vous édité le code?
Jan Hudec
1
Très probablement, votre distribution a déplacé / bin / sh vers / bin / ash plutôt que / bin / bash. Sauf si vous forcez spécifiquement votre Make à utiliser bash, il utilisera ce que / bin / sh est.
stsquad
Le même problème se produirait également dans le script shell s'il n'est PAS exécuté par bash.
Vladimir Kroz le

Réponses:

113

pushdest une bashamélioration du Bourne Shell spécifié par POSIX. pushdne peut pas être facilement implémenté en tant que commande, car le répertoire de travail actuel est une fonctionnalité d'un processus qui ne peut pas être modifiée par les processus enfants. (Une pushdcommande hypothétique pourrait faire l' chdir(2)appel et ensuite démarrer un nouveau shell, mais ... ce ne serait pas très utilisable.) pushdEst un shell intégré, tout comme cd.

Donc, changez votre script pour démarrer #!/bin/bashou stockez le répertoire de travail actuel dans une variable, faites votre travail, puis revenez en arrière. Cela dépend si vous voulez un script shell qui fonctionne sur des systèmes très réduits (par exemple, un serveur de construction Debian) ou si vous avez toujours besoin de bash.

sarnold
la source
17
OP dit qu'il est exécuté à partir de make. Il s'agirait donc de définir SHELL = /bin/bashplutôt que de démarrer le script avec #!/bin/bash.
Jan Hudec
@Jan Hudec, ah! Bonne prise. Merci.
sarnold
Mais la configuration de SHELL ne fonctionnera pas dans ce cas, voir test1dans ma réponse, stackoverflow.com/questions/5193048/bin-sh-pushd-not-found/… .
hlovdal
1
@hlovdal: Non, en effet ce ne sera pas suffisant.
Jan Hudec
1
Assurez-vous qu'il #!/bin/bashs'agit de la première ligne du fichier.
Michael Cole
29

ajouter

SHELL: = / bin / bash

en haut de votre makefile je l'ai trouvé sur une autre question Comment puis-je utiliser la syntaxe Bash dans les cibles Makefile?

Juan José Pablos
la source
Oui merci. Red Hats par défaut bash cependant sur Debian c'est vraiment sh (ou une implémentation de celui-ci). C'était mon problème.
lzap le
18

Une solution de contournement pour cela serait d'avoir une variable pour obtenir le répertoire de travail actuel. Ensuite, vous pouvez en sortir un CD pour faire n'importe quoi, puis lorsque vous en avez besoin, vous pouvez le récupérer.

c'est à dire

oldpath = `pwd`
# faites ce que fait votre script
...
...
...
# retournez au répertoire que vous vouliez pousser
cd $ oldpath
Classifié
la source
6
Vous pouvez également cddans le répertoire que vous voulez et ensuite faire cd -, pas besoin d'utiliser cette $oldpathvariable si vous n'utilisez pas cdentre les deux. La chose intéressante pushdest que chaque fois que vous l'utilisez, vous poussez un répertoire dans une pile, et ensuite vous pouvez revenir au dernier en utilisant popd, il est donc logique de l'utiliser lorsque vous allez dans plus d'un répertoire et que vous voulez un retour sûr.
Enrico
1
Si c'est juste un oneliner, les éléments suivants peuvent également fonctionner(cd /new_path ; command )
barney765
10

C'est parce que pushd est une fonction intégrée dans bash. Il n'est donc pas lié à la variable PATH et n'est pas non plus supporté par / bin / sh (qui est utilisé par défaut par make. Vous pouvez changer cela en définissant SHELL (bien que cela ne fonctionnera pas directement (test1)).

Vous pouvez à la place exécuter toutes les commandes via bash -c "...". Cela rendra les commandes, y compris pushd / popd, exécutées dans un environnement 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;"

Lors de l'exécution de make test1 et make test2, cela donne ce qui suit:

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>

Pour test1, même si bash est utilisé comme shell, chaque commande / ligne de la règle est exécutée par elle-même, donc la commande pushd est exécutée dans un shell différent de popd.

Hlovdal
la source
1
@Jan Hudec, je pense tcsh(et peut csh- être ?) > $ tcsh haig:/> exit $ csh haig:/> exit $
Terminer
Le mien fait :) En fait, ma PS1 l'est, (\u) \h:\w>mais je l'ai juste réduite à une chaîne générique maintenant pour la réponse. L'invite sous DOS se termine également par >par défaut ( $P$GIIRC), et j'aime ça.
hlovdal
Réglez SHELL avec: = not with =
cup
Le réglage "SHELL = / bin / bash" fonctionne bien pour moi, je ne sais pas comment vous l'avez fait pour ne pas fonctionner.
Isaac Freeman
4

Votre shell (/ bin / sh) essaie de trouver «pushd». Mais il ne peut pas le trouver car 'pushd', 'popd' et d'autres commandes de ce genre sont construites dans bash.

Lancez votre script en utilisant Bash (/ bin / bash) au lieu de Sh comme vous le faites maintenant, et cela fonctionnera

Joséignaciorc
la source
4
sudo dpkg-reconfigure dash 

Puis sélectionnez no.

user2438597
la source
2

Synthétiser à partir des autres réponses: pushdest spécifique à bash et vous faites en utilisant un autre shell POSIX. Il existe une solution de contournement simple pour utiliser un shell séparé pour la partie qui nécessite un répertoire différent, alors essayez simplement de le changer en:

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

(J'ai remplacé le long chemin par une extension variable. J'en suis probablement un dans le makefile et il se développe clairement dans le répertoire courant).

Puisque vous l'exécutez à partir de make, je remplacerais probablement le test par une règle make, aussi. Juste

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

(a supprimé le préfixe de répertoire actuel; vous utilisiez de toute façon un chemin relatif à certains moments) Et que de simplement faire dépendre la règle gen/SvcGenLog. Ce serait un peu plus lisible et vous pouvez le faire dépendre genscript/genmakefile.plaussi, donc le Makefilein gensera régénéré si vous modifiez le script. Bien sûr, si quelque chose d'autre affecte le contenu de Makefile, vous pouvez également faire en sorte que la règle en dépende.

Jan Hudec
la source
2

Notez que chaque ligne exécutée par un fichier make est de toute façon exécutée dans son propre shell. Si vous changez de répertoire, cela n'affectera pas les lignes suivantes. Vous avez donc probablement peu d'utilité pour pushd et popd, votre problème est plutôt l'inverse, celui de faire en sorte que le répertoire reste changé aussi longtemps que vous en avez besoin!

Mark Baker
la source
1

Exécutez "apt install bash". Il installera tout ce dont vous avez besoin et la commande fonctionnera

MatanN
la source
1

voici une méthode pour pointer

sh -> bash

exécutez cette commande sur le terminal

sudo dpkg-reconfigure dash

Après cela, vous devriez voir

ls -l /bin/sh

pointez sur / bin / bash (et non sur / bin / dash)

Référence

Muhammad Numan
la source
0

Cela devrait faire l'affaire:

( cd dirname ; pwd ); pwd

Les parenthèses démarrent un nouveau shell enfant, donc le cdrépertoire dans l'enfant uniquement, et toute commande après celui-ci entre parenthèses s'exécutera dans ce dossier. Une fois que vous avez quitté les parenthèses, vous êtes de retour là où vous étiez auparavant.

Born2Sourire
la source