/ bin / sh: pushd: não encontrado

99

Estou fazendo o seguinte dentro de um arquivo make

pushd %dir_name%

e eu recebo o seguinte erro

/bin/sh : pushd : not found

Alguém pode me dizer por que esse erro está aparecendo? Eu verifiquei minha variável $ PATH e ela contém / bin, então não acho que isso esteja causando um problema.

Pein
fonte
Não está reclamando de merda, está reclamando que não consegue encontrar pushd. O pushd está no seu $PATH?
Konerak
7
Konerak: pushd não faz sentido estar no caminho, é um bash embutido. O problema é um bash embutido, não um shell POSIX.
Jan Hudec,
Por que você editou o código?
Jan Hudec,
1
Muito provavelmente sua distribuição mudou / bin / sh para / bin / ash em vez de / bin / bash. A menos que você force especificamente o seu Make a usar o bash, ele usará o que for / bin / sh.
stsquad de
O mesmo problema ocorreria no script de shell também se ele fosse executado NÃO pelo bash.
Vladimir Kroz

Respostas:

113

pushdé um bashaprimoramento do Bourne Shell especificado por POSIX. pushdnão pode ser facilmente implementado como um comando, porque o diretório de trabalho atual é um recurso de um processo que não pode ser alterado por processos filho. (Um pushdcomando hipotético pode fazer a chdir(2)chamada e, em seguida, iniciar um novo shell, mas ... não seria muito utilizável.) pushdÉ um shell embutido, assim como cd.

Portanto, altere seu script para começar #!/bin/bashou armazene o diretório de trabalho atual em uma variável, faça seu trabalho e depois volte. Depende se você deseja um script de shell que funcione em sistemas muito reduzidos (digamos, um servidor de compilação Debian) ou se você está sempre bem solicitando bash.

Sarnold
fonte
17
OP diz que é executado a partir do make. Portanto, seria uma configuração em SHELL = /bin/bashvez de iniciar o script com #!/bin/bash.
Jan Hudec,
@Jan Hudec, ah! Boa pegada. Obrigado.
sarnold,
Mas definir SHELL não funcionará neste caso, veja test1em minha resposta, stackoverflow.com/questions/5193048/bin-sh-pushd-not-found/… .
hlovdal
1
@hlovdal: Não, na verdade não será suficiente.
Jan Hudec,
1
Certifique-se de que #!/bin/bashseja a primeira linha do arquivo.
Michael Cole
29

adicionar

SHELL: = / bin / bash

no topo do seu makefile eu encontrei em outra questão Como posso usar a sintaxe Bash nos destinos do Makefile?

Juan Jose Pablos
fonte
Sim, obrigado. O padrão do Red Hats é bash, entretanto no Debian é realmente sh (ou alguma implementação dele). Esse foi o meu problema.
lzap
18

Uma solução alternativa para isso seria fazer com que uma variável obtivesse o diretório de trabalho atual. Depois, você pode usar o cd para fazer o que quiser e, quando precisar, pode fazer o cd de volta.

ie

oldpath = `pwd`
#faça o que quer que seu script faça
...
...
...
# volte para o diretório que você queria empurrar
cd $ oldpath
Classificado
fonte
6
Você também pode cdentrar no diretório que quiser e depois fazer cd -, não há necessidade de usar essa $oldpathvariável se você não usar no cdmeio. O interessante pushdé que cada vez que você o usa, você empurra um diretório para uma pilha e, depois disso, pode voltar ao último usando popd, por isso faz sentido usá-lo quando estiver entrando em mais de um diretório e quiser um caminho de volta seguro.
Enrico
1
Se for apenas um oneliner, o seguinte também pode funcionar(cd /new_path ; command )
barney765
10

Isso ocorre porque pushd é uma função embutida no bash. Portanto, não está relacionado à variável PATH e também não é suportado por / bin / sh (que é usado por padrão pelo make. Você pode mudar isso configurando SHELL (embora não funcione diretamente (test1)).

Em vez disso, você pode executar todos os comandos bash -c "...". Isso fará com que os comandos, incluindo pushd / popd, sejam executados em um 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;"

Ao executar make test1 e make test2, ele fornece o seguinte:

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>

Para test1, embora o bash seja usado como um shell, cada linha de comando / linha na regra é executada por si só, portanto, o comando pushd é executado em um shell diferente do popd.

Hlovdal
fonte
1
@Jan Hudec, acho tcsh(e talvez csh?) > $ tcsh haig:/> exit $ csh haig:/> exit $
Termine
O meu sim :) Na verdade, meu PS1 é, (\u) \h:\w>mas eu apenas o reduzi a uma string genérica agora para a resposta. O prompt no DOS também termina com >por padrão ( $P$GIIRC), e eu gosto disso.
hlovdal
Definir SHELL com: = não com =
xícara
Definir "SHELL = / bin / bash" funciona bem para mim, não tenho certeza de como você fez isso não funcionar.
Isaac Freeman
4

Seu shell (/ bin / sh) está tentando encontrar 'pushd'. Mas ele não consegue encontrar porque 'pushd', 'popd' e outros comandos como esse são compilados no bash.

Lance seu script usando Bash (/ bin / bash) em vez de Sh como você está fazendo agora, e vai funcionar

Joseignaciorc
fonte
4
sudo dpkg-reconfigure dash 

Em seguida, selecione no.

user2438597
fonte
2

Sintetizando a partir de outras respostas: pushdé específico do bash e você está usando outro shell POSIX. Há uma solução simples para usar um shell separado para a parte que precisa de um diretório diferente, então tente alterá-lo para:

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

(Substituí o caminho longo por uma expansão variável. Provavelmente estou no makefile e ele claramente se expande para o diretório atual).

Já que você o está executando a partir do make, provavelmente também substituiria o teste por uma regra do make. Somente

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

(eliminou o prefixo do diretório atual; você estava usando o caminho relativo em alguns pontos de qualquer maneira) E então apenas faça a regra depender gen/SvcGenLog. Seria um pouco mais legível e você pode torná-lo dependente do genscript/genmakefile.pltambém, então o Makefilein genserá regenerado se você modificar o script. Obviamente, se alguma coisa afetar o conteúdo do Makefile, você também pode fazer a regra depender disso.

Jan Hudec
fonte
2

Observe que cada linha executada por um arquivo make é executada em seu próprio shell de qualquer maneira. Se você mudar de diretório, isso não afetará as linhas subsequentes. Portanto, você provavelmente usa pouco pushd e popd, seu problema é mais o oposto, é fazer com que o diretório permaneça alterado pelo tempo que você precisar!

Mark Baker
fonte
1

Execute "apt install bash" Irá instalar tudo o que precisa e o comando irá funcionar

MatanN
fonte
1

aqui está um método para apontar

sh -> bash

execute este comando no terminal

sudo dpkg-reconfigure dash

Depois disso você deve ver

ls -l /bin/sh

aponte para / bin / bash (e não para / bin / dash)

Referência

Muhammad Numan
fonte
0

Isso deve resolver o problema:

( cd dirname ; pwd ); pwd

Os parênteses iniciam um novo shell filho, portanto, cdo diretório muda apenas dentro do filho, e qualquer comando após ele entre os parênteses será executado nessa pasta. Depois de sair dos parênteses, você está de volta onde estava antes.

Born2Smile
fonte