/ bin / sh:推送:找不到


99

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

pushd %dir_name%

我得到以下错误

/bin/sh : pushd : not found

有人可以告诉我为什么出现此错误吗?我检查了$ PATH变量,它包含/ bin,所以我不认为这会引起问题。


它不是在抱怨sh,而是在抱怨找不到pushd。被推入你的 $PATH
Konerak 2011年

7
Konerak:被推挤没有意义,这是内置的bash。问题是内置的bash,而不是POSIX shell。
Jan Hudec

您为什么要修改代码?
Jan Hudec

1
您的发行版很可能已将/ bin / sh移至/ bin / ash而不是/ bin / bash。除非您专门强迫Make使用bash,否则它将使用/ bin / sh。
stsquad 2012年

如果不是由bash执行,shell脚本中也会发生同样的问题。
弗拉基米尔·克罗兹(Fladimir Kroz)2015年

Answers:


113

pushdbashPOSIX指定的Bourne Shell 的增强。pushd不能轻松地实现为命令,因为当前工作目录是进程的功能,子进程无法更改。(一个假设的pushd命令可能会执行chdir(2)调用,然后启动一个新的shell,但是...并不是很有用。)pushd是一个内置的shell,就像cd

因此,更改脚本开头#!/bin/bash或将当前工作目录存储在变量中,进行工作,然后再更改回去。取决于您是否需要在非常简化的系统(例如Debian构建服务器)上运行的Shell脚本,或者是否总是需要bash


17
OP表示它是从make运行的。因此,它将设置SHELL = /bin/bash而不是使用来启动脚本#!/bin/bash
Jan Hudec

@Jan Hudec,啊!接得好。谢谢。
sarnold 2011年

但是,设置shell会在这种情况下不工作,请test1在我的答案,stackoverflow.com/questions/5193048/bin-sh-pushd-not-found/...
hlovdal

1
@hlovdal:不,确实还不够。
Jan Hudec

1
确保#!/bin/bash是文件的第一行。
Michael Cole


18

一种解决方法是让变量获取当前的工作目录。然后,您可以使用cd退出以执行任何操作,然后在需要时使用cd返回。

oldpath =`pwd`
#执行脚本的所有操作
...
...
...
#返回您要推送的目录
cd $ oldpath

6
您也可以cd进入所需的目录,然后再执行操作cd -$oldpath如果您之间不使用该变量,则无需使用该变量cd。有趣的pushd是,每次使用该目录时,您都将目录推送到堆栈中,然后可以使用返回到最新目录popd,因此,当您要进入多个目录并需要一个目录时,可以使用该目录肯定的方法。
恩里科

1
如果仅是单线,则以下方法也可能有效(cd /new_path ; command )
barney765 '17

10

这是因为push是bash中的内置函数。因此,它与PATH变量无关,也不受/ bin / sh支持(make缺省使用它。您可以通过设置SHELL来更改它(尽管它不能直接起作用(test1)))。

您可以改为通过运行所有命令bash -c "..."。这将使命令(包括push / 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>

对于test1,即使将bash用作shell,规则中的每个命令/行也都由其自身运行,因此pushd命令在与popd不同的shell中运行。


1
@Jan Hudec,我认为tcsh(也许csh?)确实以以下方式结束了他们的提示> $ tcsh haig:/> exit $ csh haig:/> exit $
sarnold 2011年

我的确实:)实际上我的PS1是,(\u) \h:\w>但是我现在将其剥离为通用字符串以获取答案。>默认情况下,DOS中的提示也以($P$GIRC)结尾,我喜欢这样。
hlovdal

将SHELL设置为:=不使用=

设置“ SHELL = / bin / bash”对我来说很好用,不确定您如何使它不起作用。
艾萨克·弗里曼

4

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

使用Bash(/ bin / bash)而不是Sh来启动脚本,就像现在一样,它将起作用



2

从其他响应中合成:pushd是特定于bash的,并且您正在使用另一个POSIX 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,因此如果您修改脚本Makefilegen则将重新生成in 。当然,如果其他任何因素影响的内容Makefile,您也可以使规则也取决于该规则。


2

注意,make文件执行的每一行无论如何都在其自己的shell中运行。如果更改目录,则不会影响后续行。因此,您可能对push和popd没什么用,您的问题则恰恰相反,就是使目录在需要时保持更改!


1

运行“ apt install bash”,它将安装您需要的所有内容,该命令将起作用


1

这是一种指向的方法

sh-> bash

在终端上运行此命令

sudo dpkg-reconfigure dash

之后,您应该看到

ls -l /bin/sh

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

参考


0

这应该可以解决问题:

( cd dirname ; pwd ); pwd

括号会启动一个新的子外壳程序,因此cd仅更改子目录中的目录,并且括号后的任何命令都将在该文件夹中运行。退出括号后,您将回到之前的位置。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.