/ bin / sh: pushd: không tìm thấy


99

Tôi đang làm như sau bên trong một tệp tạo

pushd %dir_name%

và tôi gặp lỗi sau

/bin/sh : pushd : not found

Ai đó có thể vui lòng cho tôi biết tại sao lỗi này lại hiển thị không? Tôi đã kiểm tra biến $ PATH của mình và nó chứa / bin nên tôi không nghĩ rằng điều đó đang gây ra sự cố.


Nó không phàn nàn về sh, nó phàn nàn rằng nó không thể tìm thấy pushd. Đẩy có trong bạn $PATHkhông?
Konerak

7
Konerak: pushd không có ý nghĩa gì khi nằm trong đường dẫn, nó là một bản dựng sẵn. Vấn đề là nội trang bash , không phải là shell POSIX.
Jan Hudec

Tại sao bạn lại chỉnh sửa mã?
Jan Hudec

1
Nhiều khả năng bản phân phối của bạn đã chuyển / bin / sh thành / bin / ash thay vì / bin / bash. Trừ khi bạn bắt buộc cụ thể Make của bạn sử dụng bash, nó sẽ sử dụng bất cứ thứ gì / bin / sh là.
stsquad

Vấn đề tương tự cũng sẽ xảy ra trong tập lệnh shell nếu nó được thực thi KHÔNG bởi bash.
Vladimir Kroz

Câu trả lời:


113

pushdlà một bashcải tiến cho Bourne Shell do POSIX chỉ định. pushdkhông thể dễ dàng thực hiện dưới dạng lệnh, bởi vì thư mục làm việc hiện tại là một đặc điểm của một tiến trình mà các tiến trình con không thể thay đổi. (Một pushdlệnh giả định có thể thực hiện lệnh chdir(2)gọi và sau đó bắt đầu một trình bao mới, nhưng ... nó sẽ không thể sử dụng được.) pushdLà một nội trang của trình bao, giống như vậy cd.

Vì vậy, hãy thay đổi tập lệnh của bạn để bắt đầu bằng #!/bin/bashhoặc lưu trữ thư mục làm việc hiện tại trong một biến, thực hiện công việc của bạn, sau đó thay đổi lại. Tùy thuộc vào việc bạn muốn một tập lệnh shell hoạt động trên các hệ thống rất đơn giản (ví dụ, một máy chủ bản dựng Debian) hay nếu bạn luôn yêu cầu bash.


17
OP nói rằng nó chạy từ chế tạo. Vì vậy, nó sẽ là thiết lập SHELL = /bin/bashthay vì bắt đầu tập lệnh với #!/bin/bash.
Jan Hudec

@Jan Hudec, ah! Nắm bắt tốt. Cảm ơn.
sarnold

Nhưng cài đặt SHELL sẽ không hoạt động trong trường hợp này, hãy xem test1trong câu trả lời của tôi, stackoverflow.com/questions/5193048/bin-sh-pushd-not-found/… .
hlovdal

1
@hlovdal: Không, thực sự là không đủ.
Jan Hudec

1
Đảm bảo #!/bin/bashlà dòng đầu tiên của tệp.
Michael Cole


18

Một giải pháp cho điều này sẽ là để một biến có được thư mục làm việc hiện tại. Sau đó bạn có thể cd ra khỏi đó để làm bất cứ điều gì, rồi khi cần bạn có thể cd vào lại.

I E

oldpath = `pwd`
# làm bất cứ điều gì tập lệnh của bạn làm
...
...
...
# quay lại dir bạn muốn pushd
cd $ oldpath

6
Bạn cũng có thể cdvào thư mục bạn muốn và sau đó thực hiện cd -, không cần sử dụng $oldpathbiến đó nếu bạn không sử dụng ở giữa cd. Điều thú vị pushdlà mỗi lần bạn sử dụng nó, bạn đang đẩy một thư mục vào một ngăn xếp và sau đó bạn có thể quay lại thư mục mới nhất bằng cách sử dụng popd, vì vậy sẽ rất hợp lý khi sử dụng nó khi bạn đang đi vào nhiều thư mục và muốn một con đường trở lại chắc chắn.
Enrico

1
Nếu nó chỉ là một oneliner, sau đây cũng có thể làm việc(cd /new_path ; command )
barney765

10

Điều này là do pushd là một hàm nội trang trong bash. Vì vậy, nó không liên quan đến biến PATH và nó cũng không được hỗ trợ bởi / bin / sh (được sử dụng theo mặc định của make. Bạn có thể thay đổi điều đó bằng cách đặt SHELL (mặc dù nó sẽ không hoạt động trực tiếp (test1)).

Thay vào đó, bạn có thể chạy tất cả các lệnh bash -c "...". Điều đó sẽ làm cho các lệnh, bao gồm pushd / popd, chạy trong môi trường 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;"

Khi chạy, hãy tạo test1 và tạo test2, nó sẽ đưa ra kết quả sau:

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>

Đối với test1, mặc dù bash được sử dụng như một trình bao, mỗi lệnh / dòng trong quy tắc được chạy bởi chính nó, vì vậy lệnh pushd được chạy trong một trình bao khác với popd.


1
@Jan Hudec, tôi nghĩ tcsh(và có thể csh?) Kết thúc lời nhắc của họ bằng > :$ tcsh haig:/> exit $ csh haig:/> exit $
sarnold

Của tôi thì có :) Thực ra thì PS1 của tôi là (\u) \h:\w>vậy nhưng bây giờ tôi chỉ rút gọn nó thành một chuỗi chung để có câu trả lời. Lời nhắc trong DOS cũng kết thúc >bằng ( $P$GIIRC) theo mặc định và tôi thích điều đó.
hlovdal

Đặt SHELL với: = not with =
cup

Đặt "SHELL = / bin / bash" hoạt động tốt đối với tôi, không chắc bạn đã làm thế nào để nó không hoạt động.
Isaac Freeman,

4

Trình bao (/ bin / sh) của bạn đang cố gắng tìm 'pushd'. Nhưng nó không thể tìm thấy nó vì 'pushd', 'popd' và các lệnh khác tương tự như vậy được xây dựng trong bash.

Khởi chạy tập lệnh của bạn bằng Bash (/ bin / bash) thay vì Sh như bạn đang làm bây giờ và nó sẽ hoạt động



2

Tổng hợp từ các phản hồi khác: pushddành riêng cho từng bash và bạn đang thực hiện bằng cách sử dụng một trình bao POSIX khác. Có một giải pháp đơn giản để sử dụng shell riêng biệt cho phần cần thư mục khác, vì vậy chỉ cần thử thay đổi nó thành:

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

(Tôi đã thay thế đường dẫn dài bằng một phần mở rộng có thể thay đổi được. Tôi có thể là một đường dẫn trong makefile và nó mở rộng rõ ràng đến thư mục hiện tại).

Vì bạn đang chạy nó từ make, nên tôi cũng có thể thay thế bài kiểm tra bằng một quy tắc tạo. Chỉ

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

(bỏ tiền tố thư mục hiện tại; dù sao thì bạn cũng đang sử dụng đường dẫn tương đối ở một số điểm) Và hơn là chỉ làm cho quy tắc phụ thuộc vào gen/SvcGenLog. Nó sẽ là một chút dễ đọc hơn và bạn có thể làm cho nó phụ thuộc vào genscript/genmakefile.plquá, vì vậy Makefiletrong gensẽ được tái sinh nếu bạn sửa đổi kịch bản. Tất nhiên nếu bất kỳ điều gì khác ảnh hưởng đến nội dung của Makefile, bạn cũng có thể làm cho quy tắc phụ thuộc vào điều đó.


2

Lưu ý rằng mỗi dòng được thực thi bởi tệp thực hiện vẫn chạy trong trình bao của chính nó. Nếu bạn thay đổi thư mục, nó sẽ không ảnh hưởng đến các dòng tiếp theo. Vì vậy, bạn có thể ít sử dụng đến pushd và popd, vấn đề của bạn thì ngược lại, đó là việc giữ cho thư mục được thay đổi miễn là bạn cần!


1

Chạy "apt install bash" Nó sẽ cài đặt mọi thứ bạn cần và lệnh sẽ hoạt động


1

đây là một phương pháp để chỉ

sh -> bash

chạy lệnh này trên thiết bị đầu cuối

sudo dpkg-reconfigure dash

Sau đó bạn sẽ thấy

ls -l /bin/sh

trỏ tới / bin / bash (chứ không phải / bin / dash)

Tài liệu tham khảo


0

Điều này phải thực hiện thủ thuật:

( cd dirname ; pwd ); pwd

Các dấu ngoặc đơn bắt đầu một trình bao con mới, do đó chỉ cdthay đổi thư mục bên trong phần tử con và bất kỳ lệnh nào sau nó trong dấu ngoặc đơn sẽ chạy trong thư mục đó. Khi bạn thoát khỏi dấu ngoặc đơn, bạn đã trở lại bất cứ nơi nào bạn ở trước đây ..

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.