/bin/sh: pushd: 未找到

我在 make 文件中执行以下操作

pushd %dir_name%

我得到了下面的错误

/bin/sh : pushd : not found

Can someone please tell me why this error is showing up ? 我检查了 $PATH 变量,它包含/bin,所以我不认为这会导致问题。

146039 次浏览

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 也许吧 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.

因此,要么改变你的脚本以 #!/bin/bash开始,要么将当前的工作目录存储在一个变量中,做你的工作,然后再改回来。这取决于您是想要一个可以在非常简化的系统(比如 Debian 构建服务器)上工作的 shell 脚本,还是想要一个总是需要 bash的 shell 脚本。

这是因为 pushd 是 bash 中的一个内置函数。因此,它与 PATH 变量无关,而且/bin/sh 也不支持它(make 默认使用该变量)。您可以通过设置 SHELL 来改变这一点(尽管它不能直接工作(test1))。

相反,您可以通过 bash -c "..."运行所有命令。这将使命令(包括 pushd/popd)在 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;"

在运行 make test1和 make test2时,它提供以下内容:

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.

您的 shell (/bin/sh)正在尝试查找“ pushd”。但是它找不到它,因为“ pushd”、“ popd”和其他类似的命令都是在 bash 中构建的。

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

从其他响应综合起来: pushd是特定于 bash 的,您正在使用另一个 POSIX shell。有一个简单的解决方案,可以对需要不同目录的部分使用单独的 shell,所以只需尝试将其更改为:

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

(我用变量展开代替了长路。我可能是 makefile 文件中的一员,它显然扩展到了工作目录)。

既然您在 make 中运行它,我可能也会用 make 规则替换测试

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

(去掉了工作目录前缀,你在某些地方使用了相对路径) 而不仅仅是使规则依赖于 gen/SvcGenLog。它将更具可读性,并且您可以使它也依赖于 genscript/genmakefile.pl,因此如果您修改脚本,gen中的 Makefile将被重新生成。当然,如果有任何其他因素影响到 Makefile的内容,您也可以使规则依赖于它。

请注意,make 文件执行的每一行都在它自己的 shell 中运行。如果更改目录,则不会影响后续行。所以你可能很少使用 pushd 和 popd,你的问题是相反的,让目录保持修改,只要你需要它!

add

SHELL := /bin/bash

在你的生成文件的顶部 我在另一个问题 < a href = “ https://stackoverflow./questions/589276/How-can-i-use-Bash-sem- in-Makefile-target”> 中发现了这个问题。我怎样才能在 Makefile 目标中使用 Bash 语法?

解决这个问题的方法是让一个变量获取当前的工作目录。然后你可以从中选择做什么,当你需要的时候,你可以重新选择。

也就是说。

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

Run "apt install bash" 它会安装你需要的所有东西,这个命令也会正常工作

sudo dpkg-reconfigure dash

然后选择 no

这应该会奏效:

( cd dirname ; pwd ); pwd

括号启动一个新的子 shell,因此 cd只更改子 shell 中的目录,在括号之后的任何命令都将在该文件夹中运行。一旦你退出括号,你就会回到原来的位置。.

这里有一个指向的方法

sh -> bash

在终端上运行这个命令

sudo dpkg-reconfigure dash

这之后你应该看看

ls -l /bin/sh

指向/bin/bash (而不是/bin/ash)

参考文献