Tại sao bạn cần ./ (dấu chấm chéo) trước khi thực thi hoặc tên tập lệnh để chạy nó trong bash?


288

Khi chạy script trong bash, tôi phải viết ./ngay từ đầu:

$ ./manage.py syncdb

Nếu tôi không, tôi nhận được một thông báo lỗi:

$ manage.py syncdb
-bash: manage.py: command not found

Lý do cho điều này là gì? Tôi nghĩ .là một bí danh cho thư mục hiện tại, và do đó hai cuộc gọi này nên tương đương nhau.

Tôi cũng không hiểu tại sao tôi không cần ./khi chạy các ứng dụng, chẳng hạn như:

user:/home/user$ cd /usr/bin
user:/usr/bin$ git

(chạy mà không có ./)


4
Đây là tài liệu tốt nhất về vấn đề mà tôi đã gặp từ trước đến nay: linfo.org/dot_slash.html
odigity

Câu trả lời:


307

Bởi vì trên Unix, thông thường, thư mục hiện tại không có trong $PATH.

Khi bạn gõ một lệnh, shell sẽ tìm kiếm một danh sách các thư mục, như được chỉ định bởi PATHbiến. Thư mục hiện tại không có trong danh sách đó.

Lý do không có thư mục hiện tại trong danh sách đó là bảo mật.

Giả sử bạn đã root và đi vào thư mục người dùng khác và nhập slthay vì ls. Nếu thư mục hiện tại nằm trong PATH, shell sẽ cố gắng thực thi slchương trình trong thư mục đó (vì không có slchương trình nào khác ). slChương trình đó có thể độc hại.

Nó hoạt động với ./POSIX chỉ định rằng một tên lệnh có chứa /sẽ được sử dụng trực tiếp làm tên tệp, loại bỏ tìm kiếm trong $PATH. Bạn có thể đã sử dụng đường dẫn đầy đủ cho cùng một hiệu ứng, nhưng ./ngắn hơn và dễ viết hơn.

BIÊN TẬP

Phần đó slchỉ là một ví dụ. Các thư mục trong PATHđược tìm kiếm tuần tự và khi một trận đấu được thực hiện thì chương trình đó được thực thi. Vì vậy, tùy thuộc vào giao PATHdiện, gõ một lệnh bình thường có thể hoặc không đủ để chạy chương trình trong thư mục hiện tại.


47
Bạn không cần phải gõ nhầm bất cứ điều gì. Người dùng có thể vừa tải xuống một gói độc hại có chứa lstệp thực thi trong đó.
Juliano

13
Chỉ cần một lưu ý cho mọi người rằng đây chỉ là trong Unix chứ không phải Windows, điều này cũng tương tự ở Powershell - bạn phải làm như vậy .\my.batđể thực thi
manojlds

1
@gaearon ergh, tôi đã nói "không phải là bí danh", khi đó đáng lẽ là "hoàn toàn là bí danh".
Charles Duffy

4
Đó là một lời giải thích rất hữu ích. Hơn 20 năm trước khi tôi làm việc với DOS một chút, tôi nghĩ rằng CMD sẽ kiểm tra thư mục hiện tại, THÌ ĐÚNG, vì vậy hành vi của Linux không như tôi mong đợi, nhưng nó rất có ý nghĩa.
TecBrat

2
@cnicutar: Thật thú vị hôm nay tôi thấy rằng có một sllệnh gọi là đầu máy hơi nước mặc dù không có sẵn theo mặc định ;-)
blackSmith

51

Khi bash diễn giải dòng lệnh, nó sẽ tìm kiếm các lệnh trong các vị trí được mô tả trong biến môi trường $PATH. Để xem nó gõ:

echo $PATH

Bạn sẽ có một số đường dẫn cách nhau bởi dấu hai chấm. Như bạn sẽ thấy đường dẫn hiện tại .thường không ở trong $PATH. Vì vậy, Bash không thể tìm thấy lệnh của bạn nếu nó nằm trong thư mục hiện tại. Bạn có thể thay đổi nó bằng cách có:

PATH=$PATH:.

Dòng này thêm thư mục hiện tại $PATHđể bạn có thể làm:

manage.py syncdb

không được khuyến khích vì nó có vấn đề bảo mật, ngoài ra bạn có thể có những hành vi kỳ lạ, .thay đổi tùy theo thư mục bạn đang ở :)

Tránh:

PATH=.:$PATH

Như bạn có thể, mặt nạ, một số lệnh tiêu chuẩn và mở ra cánh cửa để vi phạm an ninh :)

Chỉ hai xu của tôi.


42

Tập lệnh của bạn, khi trong thư mục chính của bạn sẽ không được tìm thấy khi trình bao nhìn vào $PATHbiến môi trường để tìm tập lệnh của bạn.

Câu ./nói 'hãy tìm trong thư mục hiện tại cho tập lệnh của tôi thay vì xem tất cả các thư mục được chỉ định trong $PATH'.


5

Khi bạn bao gồm '.' về cơ bản, bạn đang đưa ra "đường dẫn đầy đủ" cho tập lệnh bash thực thi, vì vậy trình bao của bạn không cần kiểm tra biến PATH của bạn. Không có '.' shell của bạn sẽ tìm trong biến PATH của bạn (mà bạn có thể thấy bằng cách chạy echo $PATHđể xem liệu lệnh bạn đã nhập có tồn tại trong bất kỳ thư mục nào trên PATH của bạn không. Nếu không (như trường hợp của Manage.py), nó sẽ nói không thể tìm thấy tệp. Nó được coi là thực hành xấu khi bao gồm thư mục hiện tại trên PATH của bạn, được giải thích hợp lý ở đây: http://www.faqs.org/faqs/unix-faq/faq/part2/section- 13.html


2

Trên * nix, không giống như Windows, thư mục hiện tại thường không nằm trong $PATHbiến của bạn . Vì vậy, thư mục hiện tại không được tìm kiếm khi thực hiện các lệnh. Bạn không cần ./chạy các ứng dụng vì các ứng dụng này nằm trong $ PATH của bạn; nhiều khả năng họ đang ở /binhoặc /usr/bin.


1

Câu hỏi này đã có một số câu trả lời tuyệt vời, nhưng tôi muốn thêm rằng, nếu tệp thực thi của bạn nằm trên PATH và bạn nhận được kết quả đầu ra rất khác nhau khi bạn chạy

./executable

cho những người bạn nhận được nếu bạn chạy

executable

(giả sử bạn gặp phải thông báo lỗi với cái này chứ không phải cái kia), thì vấn đề có thể là bạn có hai phiên bản khác nhau của tệp thực thi trên máy của mình: một trên đường dẫn và phiên bản kia thì không.

Kiểm tra điều này bằng cách chạy

mà thực thi

whereis executable

Nó đã khắc phục sự cố của tôi ... Tôi có ba phiên bản thực thi, chỉ có một phiên bản được biên dịch chính xác cho môi trường.


0

Cơ sở lý luận cho /quy tắc POSIX PATH

Quy tắc đã được đề cập tại: Tại sao bạn cần ./ (dấu chấm chéo) trước khi thực thi hoặc tên tập lệnh để chạy nó trong bash? nhưng tôi muốn giải thích tại sao tôi nghĩ rằng đó là một thiết kế tốt chi tiết hơn.

Đầu tiên, một phiên bản đầy đủ rõ ràng của quy tắc là:

  • nếu đường dẫn chứa /(ví dụ ./someprog, /bin/someprog, ./bin/someprog): CWD được sử dụng và không phải là PATH
  • nếu đường dẫn không chứa /(ví dụ someprog): PATH được sử dụng và CWD không

Bây giờ, giả sử rằng đang chạy:

someprog

sẽ tìm kiếm:

  • liên quan đến CWD trước
  • liên quan đến PATH sau

Sau đó, nếu bạn muốn chạy /bin/someprogtừ bản phân phối của mình và bạn đã làm:

someprog

đôi khi nó sẽ hoạt động, nhưng những cái khác nó sẽ thất bại, bởi vì bạn có thể đang ở trong một thư mục chứa một someprogchương trình không liên quan khác .

Do đó, bạn sẽ sớm biết rằng điều này không đáng tin cậy và cuối cùng bạn sẽ luôn sử dụng các đường dẫn tuyệt đối khi bạn muốn sử dụng PATH, do đó đánh bại mục đích của PATH.

Đây cũng là lý do tại sao có các đường dẫn tương đối trong PATH của bạn là một ý tưởng thực sự tồi tệ. Tôi đang nhìn bạn ,node_modules/bin .

Ngược lại, giả sử rằng đang chạy:

./someprog

Sẽ tìm kiếm:

  • liên quan đến PATH trước
  • liên quan đến CWD sau

Sau đó, nếu bạn vừa tải xuống một tập lệnh someprogtừ kho git và muốn chạy nó từ CWD, bạn sẽ không bao giờ chắc chắn rằng đây là chương trình thực tế sẽ chạy, bởi vì có thể bản phân phối của bạn có:

/bin/someprog

đó là trong bạn PATH từ một số gói bạn đã cài đặt sau khi uống quá nhiều sau Giáng sinh năm ngoái.

Do đó, một lần nữa, bạn sẽ buộc phải luôn chạy các tập lệnh cục bộ liên quan đến CWD với các đường dẫn đầy đủ để biết bạn đang chạy gì:

"$(pwd)/someprog"

Điều này cũng sẽ vô cùng khó chịu.

Một quy tắc khác mà bạn có thể muốn đưa ra là:

đường dẫn tương đối chỉ sử dụng PATH, đường dẫn tuyệt đối chỉ CWD

nhưng một lần nữa, điều này buộc người dùng luôn phải sử dụng các đường dẫn tuyệt đối cho các tập lệnh không phải PATH với "$(pwd)/someprog".

Các /quy tắc tìm kiếm con đường cung cấp một đơn giản để nhớ giải pháp cho các vấn đề về:

  • dấu gạch chéo: không sử dụng PATH
  • không gạch chéo: chỉ sử dụng PATH

Điều này giúp bạn luôn dễ dàng biết được những gì bạn đang chạy, bằng cách dựa vào thực tế là các tệp trong thư mục hiện tại có thể được thể hiện dưới dạng ./somefilehoặc somefile, và do đó nó mang lại ý nghĩa đặc biệt cho một trong số chúng.

Đôi khi, hơi khó chịu khi bạn không thể tìm kiếm some/progliên quan PATH, nhưng tôi không thấy giải pháp nào cho vấn đề này.


-1

Khi tập lệnh không nằm trong Đường dẫn, nó bắt buộc phải làm như vậy. Để biết thêm thông tin, hãy đọc http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_01.html


5
... FYI, trong #bash trên irc.freenode.org, chúng tôi liên tục sửa chữa những hiểu lầm mà mọi người đã học được từ TLDP (đặc biệt là Hướng dẫn Bash nâng cao). Như vậy, chỉ đạo mọi người ở đó ... có thể không lý tưởng. (Tài liệu giới thiệu ưa thích của chúng tôi là mywiki.wooledge.org/BashGuide )
Charles Duffy

-2

Tất cả đều có câu trả lời tuyệt vời cho câu hỏi và có, điều này chỉ áp dụng khi chạy nó trên thư mục hiện tại trừ khi bạn bao gồm đường dẫn tuyệt đối. Xem mẫu của tôi dưới đây.

Ngoài ra, (dấu gạch chéo) có ý nghĩa với tôi khi tôi có lệnh trên thư mục con tmp2 (/ tmp / tmp2) và nó sử dụng (dấu gạch chéo kép).

MẪU VẬT:

[fifiip-172-31-17-12 tmp]$ ./StackO.sh

Hello Stack Overflow

[fifi@ip-172-31-17-12 tmp]$ /tmp/StackO.sh

Hello Stack Overflow

[fifi@ip-172-31-17-12 tmp]$ mkdir tmp2

[fifi@ip-172-31-17-12 tmp]$ cd tmp2/

[fifi@ip-172-31-17-12 tmp2]$ ../StackO.sh

Hello Stack Overflow
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.