Các mục trùng lặp trong $ PATH một vấn đề?


45

Tôi có nguồn bashrc của một vài người bạn của tôi. Vì vậy, cuối cùng tôi có các mục trùng lặp trong biến $ PATH của mình. Tôi không chắc chắn nếu đó là vấn đề cho các lệnh mất nhiều thời gian để bắt đầu. Làm thế nào để $ PATH nội bộ hoạt động trong bash? Có nhiều PATHS làm chậm thời gian khởi động của tôi không?




Câu trả lời:


42

Có nhiều mục trong $PATHkhông trực tiếp làm chậm quá trình khởi động của bạn, nhưng nó làm chậm mỗi lần bạn chạy một lệnh cụ thể trong phiên shell (không phải mỗi lần bạn chạy lệnh, vì bash duy trì bộ đệm). Sự chậm lại hiếm khi được nhận thấy trừ khi bạn có một hệ thống tệp đặc biệt chậm (ví dụ: NFS, Samba hoặc hệ thống tệp mạng khác hoặc trên Cygwin).

Các mục trùng lặp cũng hơi khó chịu khi bạn xem lại $PATHtrực quan, bạn phải lội qua nhiều hành trình hơn.

Nó đủ dễ để tránh thêm các mục trùng lặp.

case ":$PATH:" in
  *":$new_entry:"*) :;; # already there
  *) PATH="$new_entry:$PATH";; # or PATH="$PATH:$new_entry"
esac

Lưu ý bên lề: tìm nguồn cung cấp kịch bản shell của người khác có nghĩa là thực thi mã mà anh ta đã viết. Nói cách khác, bạn đang cho bạn bè của bạn truy cập vào tài khoản của bạn bất cứ khi nào họ muốn.

Lưu ý bên: .bashrckhông phải là nơi thích hợp để đặt $PATHhoặc bất kỳ biến môi trường nào khác. Các biến môi trường nên được đặt trong ~/.profile. Xem tập tin thiết lập nào sẽ được sử dụng để thiết lập các biến môi trường với bash? , Sự khác biệt giữa .bashrc và .bash_profile .


8
+1: không thể nhấn mạnh rằng "cho bạn bè của bạn quyền truy cập vào tài khoản của bạn" nhấn mạnh đủ. Ngay cả khi không có nỗ lực làm hại bạn, kịch bản của họ có thể chỉ là những gì họ cần và vẫn ăn bữa trưa của bạn khi bạn lấy nó.
msw

Một vấn đề có thể xảy ra với giải pháp này là nếu $ new_entry đã là mục đầu tiên trong PATH, thì ": $ new_entry:" sẽ không khớp. Tôi đã sửa lỗi này trong hồ sơ của mình bằng cách loại trừ dấu hai chấm ':' ban đầu.
Jeff Bauer

@JeffBauer Tôi không thấy vấn đề. Tôi sử dụng case :$PATH:và không case $PATHđể nó phù hợp ngay cả khi mục đầu tiên hoặc cuối cùng.
Gilles 'SO- ngừng trở nên xấu xa'

31

Tôi đã thấy mọi người dọn sạch các bản sao từ biến PATH của họ bằng cách sử dụng awkvà một cái gì đó như thế này:

PATH=$(printf "%s" "$PATH" | awk -v RS=':' '!a[$1]++ { if (NR > 1) printf RS; printf $1 }')

Bạn có thể thử thêm nó vào bashrc của riêng mình và đảm bảo rằng bạn đã lấy các tệp khác ở đâu đó trước khi chạy nó.

Một thay thế sẽ là sử dụng cácpathmerge tiện ích.

Đối với vấn đề tốc độ của bạn, điều này sẽ không ảnh hưởng đến thời gian khởi động của shell theo bất kỳ cách quan trọng nào nhưng nó có thể tiết kiệm thời gian thực hiện tab cho các lệnh, đặc biệt là khi không tìm thấy lệnh trong đường dẫn và nó lặp đi lặp lại tìm kiếm thông qua thư mục tìm kiếm nó.

Lưu ý về bảo mật: Bạn thực sự nên chú ý đến các cảnh báo của Gilles về bảo mật ở đây. Bằng cách tìm nguồn cung cấp một tệp thuộc sở hữu của một người dùng khác, bạn sẽ cấp miễn phí cho những người dùng đó để thực thi mã của họ với tư cách là người dùng của bạn mỗi khi bạn khởi động trình bao. Nếu bạn không tin tưởng những người dùng đó bằng mật khẩu của mình, bạn không nên tìm nguồn cung cấp các tệp shell của họ.


6
Tôi thích awk one-liner, nhưng nó in một ORS ':'. Vì vậy, tôi đã sửa đổi nó thành đọcPATH=$(echo "$PATH" | awk -v RS=':' -v ORS=":" '!a[$1]++{if (NR > 1) printf ORS; printf $a[$1]}')
gkb0986

Các dấu vết :không chỉ là một vấn đề thẩm mỹ. Nó cũng giống như thêm .vào đường dẫn của bạn, điều này có khả năng nguy hiểm.
wvducky

Tôi đã chỉnh sửa câu trả lời để bao gồm bản sửa lỗi từ gkb0986.
Tim Lesher

@TimLesher Lý do tôi chưa bao giờ chỉnh sửa bằng câu trả lời là nó không hoạt động với tôi .... và bản gốc không có tác dụng (bao gồm cả việc không để lại dấu phân cách. Tôi không biết sự khác biệt là gì .
Caleb

1
@ gkb0986 Giải pháp này vẫn thất bại nếu đường dẫn chứa một không gian thoát, chẳng hạn như PATH = / bin: / foo \ bar: / usr / bin. Tôi đã tìm thấy một biến thể tránh điều này tại unix.stackexchange.com/a/124517/106102
maharvey67

13

Dựa trên câu trả lời @Gilles, bạn có thể gói nó trong một chức năng để giảm thiểu việc gõ:

function addToPATH {
  case ":$PATH:" in
    *":$1:"*) :;; # already there
    *) PATH="$1:$PATH";; # or PATH="$PATH:$1"
  esac
}

addToPATH /Applications/AIRSDK_Compiler/bin
addToPATH ~/.local/lib/npm/bin

1
Hầu hết các câu trả lời thực tế có thể sử dụng (cấp cao, có lẽ).
ijoseph

3

Chỉ có kết quả khớp đầu tiên $PATHđược thực thi, do đó, mọi mục nhập tiếp theo sẽ không được xử lý sau đó. Đó là lý do tại sao đôi khi bạn nên điều chỉnh lại thứ tự của các mục trong $PATHđể làm cho môi trường của bạn hoạt động như mong đợi.

Để trả lời câu hỏi của bạn: đây không phải là nguyên nhân khởi động chậm.


1
Nhưng phải mất nhiều thời gian hơn khi tôi gõ một lệnh không tồn tại. Nó sẽ tìm kiếm cùng một thư mục hai lần cho lệnh.
balki

@balki Ý bạn là hoàn thành một lệnh với TAB? Trong trường hợp đó, bạn nên kiểm tra xem bạn có hoàn thành định nghĩa không complete -c which -a. Bạn nên xóa -atham số. Bạn có thể kiểm tra bằng cách ban hành lệnh : complete | grep which.
Rajish

Nó vẫn có thể là một vấn đề nếu nó tìm kiếm cùng một thư mục mà nó không có nhiều lần trước khi tìm thấy nó.
Random832

-1

Để ngăn các mục trùng lặp trong PATH của tôi, tôi đã phải đặt các mục sau vào BÓNG ~ / .bash_profile và ~ / .bashrc:

PATH=$(echo $(sed 's/:/\n/g' <<< $PATH | sort | uniq) | sed -e 's/\s/':'/g')

Hạn chế chính là nó sắp xếp các mục PATH, nhưng tôi nghĩ rằng tôi có thể sống với điều đó.


Thứ tự tìm kiếm PATH khá quan trọng.
Steven Shaw
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.