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


99

Я роблю наступне всередині файлу make

pushd %dir_name%

і я отримую наступну помилку

/bin/sh : pushd : not found

Може хтось скажіть мені, чому ця помилка з'являється? Я перевірив свою змінну $ PATH і вона містить / bin, тому я не думаю, що це викликає проблеми.


Він не скаржиться на sh, він скаржиться, що не може знайти pushd. Чи є у вас пудд $PATH?
Конерак

7
Konerak: pushd не має сенсу бути на шляху, це вбудований баш. Проблема в тому, що bash вбудований, а не оболонка POSIX.
Ян Худек

Чому ви редагували код?
Ян Худек

1
Швидше за все, ваш дистрибутив перемістився / bin / sh до / bin / ash, а не / bin / bash. Якщо ви спеціально не змусите ваш Make використовувати bash, він буде використовувати все, що є / bin / sh.
stsquad

Ця ж проблема може трапитися і в сценарії оболонки, якщо вона виконується НЕ bash.
Володимир Кроз

Відповіді:


113

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

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


17
ОП каже, що це працює від make. Тож це буде налаштування, SHELL = /bin/bashа не запуск сценарію з #!/bin/bash.
Ян Худек

@Jan Hudec, ах! Хороший улов. Дякую.
sarnold

Але налаштування SHELL не спрацює в цьому випадку, дивіться test1у моїй відповіді stackoverflow.com/questions/5193048/bin-sh-pushd-not-found/… .
hlovdal

1
@hlovdal: Ні, насправді цього буде недостатньо.
Ян Худек

1
Переконайтеся, що #!/bin/bashце перший рядок файлу.
Майкл Коул

29

додати

SHELL: = / bin / bash

У верхній частині вашого makefile я знайшов це з іншого питання Як я можу використовувати синтаксис Bash у цілях Makefile?


Так, дякую. Red Hats за замовчуванням грати, проте на Debian це дійсно sh (або деяка реалізація цього). Це було моє питання.
lzap

18

Вирішенням цього може бути зміна отримати поточний робочий каталог. Тоді ви можете вийти з нього, щоб зробити що завгодно, тоді, коли вам це потрібно, ви зможете повернути його назад.

тобто

oldpath = `pwd`
# все, що робить ваш сценарій
...
...
...
# поверніться до того режисера, який ви хотіли натиснути
cd $ oldpath

6
Ви також можете cdувійти до потрібного каталогу та згодом cd -, не потрібно використовувати цю $oldpathзмінну, якщо ви не будете використовувати cdміж ними. Цікавим pushdє те, що кожного разу, коли ви користуєтесь ним, ви штовхаєте каталог у стек, а згодом ви можете повернутися до останнього, використовуючи його popd, тому є сенс використовувати його, коли ви збираєтеся в більш ніж один каталог і хочете вірний шлях назад.
Енріко

1
Якщо це просто oneliner, може також працювати наступне(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.


1
@Jan Hudec, я думаю tcsh(а може бути csh?) > $ tcsh haig:/> exit $ csh haig:/> exit $
Закінчують

Моя є :) Насправді мій PS1 є, (\u) \h:\w>але я просто зняв його на загальну нитку зараз для відповіді. Підказка в DOS також закінчується >за замовчуванням ( $P$GIIRC), і мені це подобається.
hlovdal

Встановіть SHELL за допомогою: = not with =
чашка

Налаштування "SHELL = / bin / bash" для мене добре працює, не знаю, як у вас це не працює.
Ісаак Фріман

4

Ваша оболонка (/ bin / sh) намагається знайти "pushd". Але він не може знайти його, оскільки "pushd", "popd" та інші подібні команди вбудовані в bash.

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



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

(Я замінив довгий шлях змінним розширенням. Я, мабуть, один у 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занадто, так що Makefileв genбуде відновлений , якщо ви зміните сценарій. Звичайно, якщо що-небудь інше впливає на зміст Makefile, ви можете зробити так, щоб правило залежало і від цього.


2

Зауважте, що кожен рядок, виконаний файлом make, у будь-якому випадку запускається у власній оболонці. Якщо ви зміните каталог, це не вплине на наступні рядки. Тож вам, мабуть, мало користі для pushd та popd, ваша проблема скоріше навпаки, як отримати каталог, щоб не змінюватись так довго, як вам це потрібно!


1

Запустіть "apt install bash" Він встановить усе необхідне і команда буде працювати


1

ось спосіб вказати

ш -> баш

запустіть цю команду на терміналі

sudo dpkg-reconfigure dash

Після цього ви повинні побачити

ls -l /bin/sh

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

Довідково


0

Слід зробити трюк:

( cd dirname ; pwd ); pwd

В дужках запускається нова дочірня оболонка, таким чином, cdзмінюється каталог тільки в дочірній, і будь-яка команда після нього в дужках буде виконуватися в цій папці. Після виходу з дужок ви знову опинитесь там, де ви були раніше.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.