/ bin / sh: pushd: no encontrado

99

Estoy haciendo lo siguiente dentro de un archivo make

pushd %dir_name%

y me sale el siguiente error

/bin/sh : pushd : not found

¿Alguien puede decirme por qué aparece este error? Revisé mi variable $ PATH y contiene / bin, así que no creo que eso esté causando un problema.

Pein
fuente
No se queja de sh, se queja de que no puede encontrar pushd. ¿Está empujado en su $PATH?
Konerak
7
Konerak: pushd no tiene sentido estar en camino, es un bash incorporado. El problema es que un bash incorporado, no un shell POSIX.
Jan Hudec
¿Por qué editaste el código?
Jan Hudec
1
Lo más probable es que su distribución haya movido / bin / sh a / bin / ash en lugar de / bin / bash. A menos que fuerce específicamente a su Make a usar bash, usará lo que sea / bin / sh.
stsquad
El mismo problema sucedería en el script de shell también si no lo ejecuta bash.
Vladimir Kroz

Respuestas:

113

pushdes una bashmejora del Bourne Shell especificado por POSIX. pushdno se puede implementar fácilmente como un comando, porque el directorio de trabajo actual es una característica de un proceso que los procesos secundarios no pueden cambiar. (Un pushdcomando hipotético podría realizar la chdir(2)llamada y luego iniciar un nuevo shell, pero ... no sería muy útil.) pushdEs un shell incorporado, como cd.

Entonces, cambie su secuencia de comandos para comenzar #!/bin/basho almacene el directorio de trabajo actual en una variable, haga su trabajo y luego vuelva a cambiar. Depende de si desea un script de shell que funcione en sistemas muy reducidos (por ejemplo, un servidor de compilación de Debian) o si está bien siempre requiriendo bash.

sarnold
fuente
17
OP dice que se ejecuta desde make. Por lo tanto, sería configurar en SHELL = /bin/bashlugar de comenzar el script con #!/bin/bash.
Jan Hudec
@Jan Hudec, ¡ah! Buena atrapada. Gracias.
sarnold
Pero configurar SHELL no funcionará en este caso, vea test1en mi respuesta, stackoverflow.com/questions/5193048/bin-sh-pushd-not-found/… .
hlovdal
1
@hlovdal: No, de hecho no será suficiente.
Jan Hudec
1
Asegúrese de que #!/bin/bashsea ​​la primera línea del archivo.
Michael Cole
18

Una solución alternativa para esto sería hacer que una variable obtenga el directorio de trabajo actual. Luego puede sacarlo de él para hacer lo que sea, luego, cuando lo necesite, puede volver a ingresar.

es decir

oldpath = `pwd`
#haga lo que haga su script
...
...
...
# vuelve al directorio que querías empujar
cd $ oldpath
Clasificado
fuente
6
También puede cdingresar al directorio que desee y luego hacerlo cd -, no es necesario que use esa $oldpathvariable si no usa cdentremedias. Lo interesante de esto pushdes que cada vez que lo usa, está insertando un directorio en una pila, y luego puede volver al último uso popd, por lo que tiene sentido usarlo cuando ingresa a más de un directorio y desea un camino seguro de regreso.
Enrico
1
Si es solo un delineador, lo siguiente también puede funcionar(cd /new_path ; command )
barney765
10

Esto se debe a que pushd es una función incorporada en bash. Por lo tanto, no está relacionada con la variable PATH y tampoco es compatible con / bin / sh (que se usa por defecto en make. Puede cambiar eso configurando SHELL (aunque no funcionará directamente (test1)).

En su lugar, puede ejecutar todos los comandos bash -c "...". Eso hará que los comandos, incluidos pushd / popd, se ejecuten en un entorno 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;"

Al ejecutar make test1 y make test2 da lo siguiente:

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, aunque bash se usa como shell, cada comando / línea de la regla se ejecuta por sí mismo, por lo que el comando pushd se ejecuta en un shell diferente al de popd.

hlovdal
fuente
1
@Jan Hudec, creo tcsh(¿y tal vez csh?) Terminar su mensaje con > :$ tcsh haig:/> exit $ csh haig:/> exit $
sarnold
El mío lo hace :) En realidad, mi PS1 lo es, (\u) \h:\w>pero ahora lo reduje a una cadena genérica para la respuesta. El indicador en DOS también termina >por defecto con ( $P$GIIRC), y eso me gusta.
hlovdal
Configure SHELL con: = no con =
taza
La configuración de "SHELL = / bin / bash" funciona bien para mí, no estoy seguro de cómo conseguiste que no funcionara.
Isaac Freeman
4

Su shell (/ bin / sh) está tratando de encontrar 'pushd'. Pero no puede encontrarlo porque 'pushd', 'popd' y otros comandos como ese están construidos en bash.

Ejecute su script usando Bash (/ bin / bash) en lugar de Sh como lo está haciendo ahora, y funcionará

joseignaciorc
fuente
4
sudo dpkg-reconfigure dash 

Luego seleccione no.

usuario2438597
fuente
2

Sintetizar a partir de las otras respuestas: pushdes específico de bash y está utilizando otro shell POSIX. Hay una solución alternativa simple para usar un shell separado para la parte que necesita un directorio diferente, así que intente cambiarlo a:

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

(Reemplacé la ruta larga con una expansión variable. Probablemente sea una en el archivo MAKE y claramente se expanda al directorio actual).

Dado que lo está ejecutando desde make, probablemente también reemplazaría la prueba con una regla de make. Sólo

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

(eliminó el prefijo del directorio actual; de todos modos, estaba usando una ruta relativa en algunos puntos) Y luego haga que la regla dependa de gen/SvcGenLog. Sería un poco más fácil de leer y que puede hacer que dependen de la genscript/genmakefile.pldemasiado, por lo que el Makefileen gense regenerará si modifica la secuencia de comandos. Por supuesto, si algo más afecta el contenido del Makefile, puede hacer que la regla también dependa de eso.

Jan Hudec
fuente
2

Tenga en cuenta que cada línea ejecutada por un archivo make se ejecuta en su propio shell de todos modos. Si cambia de directorio, no afectará a las líneas siguientes. Así que probablemente tenga poco uso para pushd y popd, su problema es más el opuesto, ¡el de hacer que el directorio permanezca cambiado durante el tiempo que lo necesite!

Mark Baker
fuente
1

Ejecute "apt install bash" Instalará todo lo que necesita y el comando funcionará

MatanN
fuente
1

aquí hay un método para señalar

sh -> bash

ejecutar este comando en la terminal

sudo dpkg-reconfigure dash

Después de esto deberías ver

ls -l /bin/sh

apuntar a / bin / bash (y no a / bin / dash)

Referencia

Muhammad Numan
fuente
0

Esto debería hacer el truco:

( cd dirname ; pwd ); pwd

Los paréntesis inician un nuevo shell secundario, por lo que cdcambia el directorio solo dentro del niño, y cualquier comando después de él dentro del paréntesis se ejecutará en esa carpeta. Una vez que salga del paréntesis, volverá a estar donde estaba antes.

Born2Smile
fuente