/ bin / sh: pushd: не найдено

99

Я делаю следующее внутри файла make

pushd %dir_name%

и я получаю следующую ошибку

/bin/sh : pushd : not found

Может кто-нибудь сказать мне, почему появляется эта ошибка? Я проверил свою переменную $ PATH, и она содержит / bin, поэтому не думаю, что это вызывает проблему.

Пейн
источник
Он не жалуется на sh, он жалуется, что не может найти pushd. Толкается в твоем $PATH?
Konerak 04
7
Конерак: pushd не имеет смысла быть в пути, это встроенный bash. Проблема заключается во встроенном bash , а не в оболочке POSIX.
Ян Худек,
Почему вы отредактировали код?
Ян Худек
1
Скорее всего, ваш дистрибутив переместил / bin / sh в / bin / ash, а не / bin / bash. Если вы специально не заставите свой Make использовать bash, он будет использовать то, что есть / bin / sh.
stsquad
Такая же проблема может возникнуть и в сценарии оболочки, если он выполняется НЕ с помощью bash.
Владимир Кроз

Ответы:

113

pushdявляется bashусовершенствованием оболочки Bourne Shell, указанной в POSIX. pushdне может быть легко реализован как команда, потому что текущий рабочий каталог - это функция процесса, которая не может быть изменена дочерними процессами. (Гипотетическая pushdкоманда может выполнить chdir(2)вызов, а затем запустить новую оболочку, но ... она не очень удобна.) pushd- это встроенная оболочка, как и cd.

Итак, либо измените свой сценарий, чтобы начать с него, #!/bin/bashлибо сохраните текущий рабочий каталог в переменной, выполните свою работу, а затем вернитесь обратно. Зависит от того, нужен ли вам сценарий оболочки, который работает в очень ограниченных системах (скажем, на сервере сборки Debian), или если вы всегда в порядке, требуя bash.

Сарнольд
источник
17
OP говорит, что запускается от make. Таким образом, это будет установка, SHELL = /bin/bashа не запуск сценария с #!/bin/bash.
Ян Худек
@ Ян Худек, ах! Хороший улов. Спасибо.
sarnold 04
Но установка SHELL в этом случае не сработает, см. test1Мой ответ stackoverflow.com/questions/5193048/bin-sh-pushd-not-found/… .
hlovdal
1
@hlovdal: Нет, этого действительно мало.
Ян Худек
1
Убедитесь, что #!/bin/bashэто первая строка файла.
Майкл Коул,
29

Добавить

ОБОЛОЧКА: = / bin / bash

в верхней части вашего make-файла я нашел его по другому вопросу. Как я могу использовать синтаксис Bash в целях Makefile?

Хуан Хосе Паблос
источник
Да спасибо. Red Hats по умолчанию использует bash, однако в Debian это действительно sh (или какая-то его реализация). Это была моя проблема.
lzap
18

Обходным путем для этого было бы получение переменной текущего рабочего каталога. Затем вы можете выйти из него, чтобы сделать что угодно, а затем, когда вам это нужно, вы можете снова войти.

т.е.

oldpath = `pwd`
# делайте то, что делает ваш скрипт
...
...
...
# вернуться в каталог, который вы хотели нажатьd
cd $ oldpath
Секретный
источник
6
Вы также можете cdвойти в каталог, который хотите, и после этого cd -, нет необходимости использовать эту $oldpathпеременную, если вы не будете использовать cdпромежуточный. Интересно то, pushdчто каждый раз, когда вы его используете, вы помещаете каталог в стек, а после этого вы можете вернуться к последнему используемому popd, поэтому имеет смысл использовать его, когда вы переходите в более чем один каталог и хотите верный путь назад.
Энрико,
1
Если это всего лишь один лайнер, то следующее может также сработать(cd /new_path ; command )
barney765
10

Это потому, что 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>

Для test1, даже если bash используется в качестве оболочки, каждая команда / строка в правиле запускается сама по себе, поэтому команда pushd запускается в другой оболочке, чем popd.

Hlovdal
источник
1
@Jan Hudec, я думаю tcsh(а может быть csh?) > $ tcsh haig:/> exit $ csh haig:/> exit $
Заканчивают
У меня есть :) На самом деле мой PS1 есть, (\u) \h:\w>но я просто разделил его до общей строки для ответа. Приглашение в DOS также заканчивается на >по умолчанию ( $P$GIIRC), и мне это нравится.
hlovdal 04
Установите SHELL с: = not with =
cup
Установка "SHELL = / bin / bash" отлично работает для меня, не знаю, как вы заставили ее не работать.
Исаак Фриман
4

Ваша оболочка (/ bin / sh) пытается найти "pushd". Но он не может его найти, потому что pushd, popd и другие подобные команды встроены в bash.

Запустите сценарий, используя Bash (/ bin / bash) вместо Sh, как вы делаете сейчас, и он будет работать

Joseignaciorc
источник
4
sudo dpkg-reconfigure dash 

Затем выберите no.

user2438597
источник
2

Синтез на основе других ответов: pushdспецифичен для bash, и вы делаете, что используете другую оболочку POSIX. Существует простой обходной путь - использовать отдельную оболочку для части, для которой нужен другой каталог, поэтому просто попробуйте изменить его на:

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

(Я заменил длинный путь расширением переменной. Я, вероятно, есть один в make-файле, и он явно расширяется до текущего каталога).

Поскольку вы запускаете его из 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слишком, так что Makefileв genбудет восстановлен , если вы измените сценарий. Конечно, если что-то еще влияет на содержимое Makefile, вы можете сделать правило зависимым и от этого.

Ян Худек
источник
2

Обратите внимание, что каждая строка, выполняемая файлом make, в любом случае запускается в своей собственной оболочке. Если вы смените каталог, это не повлияет на последующие строки. Таким образом, вы, вероятно, мало используете pushd и popd, ваша проблема скорее противоположная, проблема с тем, чтобы каталог оставался измененным столько, сколько вам нужно!

Марк Бейкер
источник
1

Запустите "apt install bash". Он установит все, что вам нужно, и команда заработает.

MatanN
источник
1

вот способ указать

ш -> баш

запустите эту команду на терминале

sudo dpkg-reconfigure dash

После этого вы должны увидеть

ls -l /bin/sh

указать на / bin / bash (а не на / bin / dash)

Ссылка

Мухаммад Нуман
источник
0

Это должно помочь:

( cd dirname ; pwd ); pwd

Скобки запускают новую дочернюю оболочку, таким образом, cdкаталог изменяет только дочернюю оболочку, и любая команда после нее в круглых скобках будет выполняться в этой папке. Как только вы выйдете из скобок, вы снова окажетесь там, где были раньше.

Born2Smile
источник