[linux] /bin/sh: pushd: not found

I am doing the following inside a make file

pushd %dir_name%

and i get the following error

/bin/sh : pushd : not found

Can someone please tell me why this error is showing up ? I checked my $PATH variable and it contains /bin so I don't think that is causing a problem.

This question is related to linux

The answer is


Your shell (/bin/sh) is trying to find 'pushd'. But it can't find it because 'pushd','popd' and other commands like that are build in bash.

Launch you script using Bash (/bin/bash) instead of Sh like you are doing now, and it will work


Run "apt install bash" It will install everything you need and the command will work


pushd is a bash enhancement to the POSIX-specified Bourne Shell. pushd cannot be easily implemented as a command, because the current working directory is a feature of a process that cannot be changed by child processes. (A hypothetical pushd command might do the chdir(2) call and then start a new shell, but ... it wouldn't be very usable.) pushd is a shell builtin, just like cd.

So, either change your script to start with #!/bin/bash or store the current working directory in a variable, do your work, then change back. Depends if you want a shell script that works on very reduced systems (say, a Debian build server) or if you're fine always requiring bash.


add

SHELL := /bin/bash

at the top of your makefile I have found it on another question How can I use Bash syntax in Makefile targets?


This ought to do the trick:

( cd dirname ; pwd ); pwd

The parentheses start a new child shell, thus the cd changes the directory within the child only, and any command after it within the parentheses will run in that folder. Once you exit the parentheses you are back in wherever you were before..


A workaround for this would be to have a variable get the current working directory. Then you can cd out of it to do whatever, then when you need it, you can cd back in.

i.e.

oldpath=`pwd`
#do whatever your script does
...
...
...
# go back to the dir you wanted to pushd
cd $oldpath

here is a method to point

sh -> bash

run this command on terminal

sudo dpkg-reconfigure dash

After this you should see

ls -l /bin/sh

point to /bin/bash (and not to /bin/dash)

Reference


Synthesizing from the other responses: pushd is bash-specific and you are make is using another POSIX shell. There is a simple workaround to use separate shell for the part that needs different directory, so just try changing it to:

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

(I substituted the long path with a variable expansion. I probably is one in the makefile and it clearly expands to the current directory).

Since you are running it from make, I would probably replace the test with a make rule, too. Just

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

(dropped the current directory prefix; you were using relative path at some points anyway) And than just make the rule depend on gen/SvcGenLog. It would be a bit more readable and you can make it depend on the genscript/genmakefile.pl too, so the Makefile in gen will be regenerated if you modify the script. Of course if anything else affects the content of the Makefile, you can make the rule depend on that too.


Note that each line executed by a make file is run in its own shell anyway. If you change directory, it won't affect subsequent lines. So you probably have little use for pushd and popd, your problem is more the opposite, that of getting the directory to stay changed for as long as you need it!


This is because pushd is a builtin function in bash. So it is not related to the PATH variable and also it is not supported by /bin/sh (which is used by default by make. You can change that by setting SHELL (although it will not work directly (test1)).

You can instead run all the commands through bash -c "...". That will make the commands, including pushd/popd, run in a bash environment (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;"

When running make test1 and make test2 it gives the following:

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>

For test1, even though bash is used as a shell, each command/line in the rule is run by itself, so the pushd command is run in a different shell than the popd.


sudo dpkg-reconfigure dash 

Then select no.