Một cách thoải mái hơn để chỉnh sửa $ PATH dài?


35

Tôi muốn thêm, trong ~ / .bashrc, một vài thư mục vào $ PATH của tôi.

$ PATH của tôi khá dài nên hơi khó để xem nó chứa những thư mục nào và theo thứ tự nào.

Tôi biết tôi có thể sửa đổi ~ / .bashrc của mình thành:

PATH=$PATH:/some/dir
PATH=$PATH:/another/dir:/yet/another
PATH=$PATH:/and/another
...

nó sẽ làm cho nó dễ đọc hơn Nhưng tôi đã tự hỏi nếu trong những năm qua Bash đã có được một số cú pháp giúp việc xác định một PATH dài dễ dàng hơn. Ví dụ: tôi đang mơ tưởng về một cú pháp tương tự như:

PATH=:((
  /some/dir
  /another/dir
  /yet/another
  /and/another
  ...
))

Tôi biết cú pháp như vậy là không hợp lệ. Tôi đã tự hỏi nếu có một cái gì đó dễ dàng. Lanhung?


Hướng dẫn truyền thống để thiết lập đường dẫn qua PATH=foo:$PATHcó vẻ như sai vì nó giữ mức tăng trưởng mỗi lần source ~/.bashrcvà thậm chí exec bashkhông thể giúp đỡ kể từ khi $PATHexport.
林果

Câu trả lời:


25

Tôi sử dụng một tập hợp các hàm tiện lợi để thêm trước hoặc nối thêm một đường dẫn đến một biến. Các hàm xuất hiện trong tarball phân phối cho Bash trong một tệp đóng góp có tên là "pathfuncs".

  • add_path sẽ thêm mục vào cuối biến PATH
  • pre_path sẽ thêm mục vào đầu biến PATH
  • del_path sẽ xóa mục nhập khỏi biến PATH, bất kể nó ở đâu

Nếu bạn chỉ định một biến làm đối số thứ hai, nó sẽ sử dụng biến đó thay vì PATH.

Để thuận tiện, đây là:

# is $1 missing from $2 (or PATH) ?
no_path() {
    eval "case :\$${2-PATH}: in *:$1:*) return 1;; *) return 0;; esac"
}
# if $1 exists and is not in path, append it
add_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="\$${2:-PATH}:$1"
}
# if $1 exists and is not in path, prepend it
pre_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="$1:\$${2:-PATH}"
}
# if $1 is in path, remove it
del_path () {
  no_path $* || eval ${2:-PATH}=`eval echo :'$'${2:-PATH}: |
    sed -e "s;:$1:;:;g" -e "s;^:;;" -e "s;:\$;;"`
}

Nếu bạn thêm chúng vào tệp khởi động bash của mình, bạn có thể thêm vào PATH của mình như thế này:

pre_path $HOME/bin
add_path /sbin
add_path /usr/sbin

Hoặc chỉ định một biến khác:

pre_path $HOME/man MANPATH
pre_path $HOME/share/man MANPATH
add_path /usr/local/man MANPATH
add_path /usr/share/man MANPATH

Tôi sử dụng phương thức này trong các tệp RC của mình, đặt pre_path trước và add_paths thứ hai. Nó làm cho tất cả các thay đổi đường dẫn của tôi dễ hiểu trong nháy mắt. Một lợi ích khác là các dòng đủ ngắn để tôi có thể thêm một nhận xét kéo dài trên một dòng nếu cần thiết.

Và vì đây là các hàm, bạn có thể sử dụng chúng một cách tương tác từ dòng lệnh, chẳng hạn như bằng cách nói add_path $(pwd)để thêm thư mục hiện tại vào đường dẫn.


Cảm ơn. Tôi đã kiểm tra mã của bạn và nó hoạt động. Đáng ngạc nhiên, tôi cũng tìm thấy một cách sử dụng cho del_path (A "." Leo vào ĐƯỜNG của tôi trong một số tình huống, ma quỷ biết từ đâu, vì vậy tôi đã làm del_path .).
Niccolo M.

Chào. có thể lấy nguồn (bao gồm) đường dẫn này từ tập lệnh bashrc hay tôi nên sao chép / dán chúng vào đó?
Cristiano

@Cristiano Hoặc là sẽ làm việc. Nó thực sự tùy thuộc vào bạn.
Sao biển

11

OK, tôi đã tìm ra giải pháp sau đây, mà tôi nghĩ là thanh lịch (theo cú pháp shell). Nó sử dụng cú pháp mảng của Bash và cũng là một cách gọn gàng để nối các phần tử:

paths=(
  /some/dir
  /another/dir
  '/another/dir with spaces in it'
  /yet/another
  /and/another
  /end
)
paths_joined=$( IFS=: ; echo "${paths[*]}" )

PATH=$paths_joined:$PATH

CỨNG!

Hóa ra giải pháp này có một vấn đề : Không giống như các giải pháp của @terdon và @Starfish, trước tiên, nó không kiểm tra xem các đường dẫn đã có trong PATH chưa. Vì vậy, vì tôi muốn đặt mã này vào ~ / .bashrc (chứ không phải trong ~ / .profile), các đường dẫn trùng lặp sẽ leo vào PATH. Vì vậy, đừng sử dụng giải pháp này (trừ khi bạn đặt nó vào ~ / .profile (hoặc, tốt hơn, ~ / .bash_profile vì nó có cú pháp cụ thể của Bash)).


1
Rất đẹp. Bạn có thể vui lòng chấp nhận câu trả lời để những người khác không đến đây để đưa ra giải pháp khi bạn đã tìm thấy câu trả lời không? Cảm ơn
Cơ bản

Đường dẫn trùng lặp không thực sự là một vấn đề. Rất có khả năng là bạn sẽ không có đủ các thư mục PATHđể thực sự gây ra các vấn đề về hiệu năng (đặc biệt là khi shell lưu trữ các tra cứu thành công).
chepner

5

Tôi sử dụng chức năng dưới đây trong của tôi ~/.bashrc. Đó là thứ tôi nhận được từ một sysadmin trong phòng thí nghiệm cũ của tôi nhưng tôi không nghĩ anh ấy đã viết chúng. Chỉ cần thêm những dòng này vào ~/.profilehoặc ~/.bashrc:

pathmunge () {
        if ! echo $PATH | /bin/grep -Eq "(^|:)$1($|:)" ; then
           if [ "$2" = "after" ] ; then
              PATH=$PATH:$1
           else
              PATH=$1:$PATH
           fi
        fi
}

Điều này có những lợi thế khác nhau:

  • Thêm thư mục mới vào $PATHlà tầm thường : pathmunge /foo/bar;
  • Nó tránh các mục trùng lặp;
  • Bạn có thể chọn thêm một mục mới vào đầu ( pathmunge /foo/barhoặc cuối ( pathmunge /foo/barsau) của $PATH.

Tệp khởi tạo shell của bạn sau đó sẽ chứa một cái gì đó như:

pathmunge /some/dir
pathmunge /another/dir
pathmunge '/another/dir with spaces in it'
pathmunge /yet/another
pathmunge /and/another
pathmunge /end

Cảm ơn. Nhưng tôi sẽ chọn giải pháp của @ Starfish vì nó không sinh sản grep.
Niccolo M.

2
@NiccoloM. không có vấn đề, chấp nhận những gì bạn thích Tuy nhiên, hãy cẩn thận với cách tiếp cận của sao biển, nó sẽ thực thi mã tùy ý thông qua evalđể bạn có thể gây ra một số thiệt hại nghiêm trọng nếu bạn chạy nó với đối số sai.
terdon

Lưu ý rằng chức năng nhanh hơn tồn tại trong redhat để làm điều đó mà không cần lệnh bên ngoài grep, xem bugzilla.redhat.com/show_bug.cgi?id=544652#c7
林果皞

4

Tôi muốn thêm, trong ~ / .bashrc, một vài thư mục vào $ PATH của tôi.

Tôi sử dụng như sau trong Cygwin. Nó sẽ hoạt động trong các phiên bản khác của bash. Bạn có thể loại bỏ unset PATHđể xây dựng trên hiện tại của bạn PATH(nếu bạn làm điều này, bạn có thể phải tìm ra cách thêm các :dấu phân cách chính xác).

Chú thích:

  • Tôi đã từng có chức năng này trong một bashchức năng nhưng đã mất nó sau một sự cố đĩa.

Trong tôi .bash_profile:

# Build up the path using the directories in ~/.path_elements
unset PATH
while read line; do 
  PATH="${PATH}$line"; 
done < ~/.path_elements

...

# Add current directory to path
export PATH=".:${PATH}"

Trong ~/.path_elements:

/home/DavidPostill/bin:
/usr/local/bin:
/usr/bin:
/c/Windows/system32:
/c/Windows

Cảm ơn. Câu trả lời của bạn đã truyền cảm hứng cho tôi để làm việc trên giải pháp giống như. (Theo sở thích của tôi, việc lưu trữ các đường dẫn trong một tệp riêng biệt là một điều phiền phức.)
Niccolo M.

1

Tôi sử dụng điều này trong .bashrc của tôi (và cả .zshrc của tôi, vì tôi thường sử dụng zsh khi có sẵn thay vì bash). Cấp, nó yêu cầu tôi thêm các thư mục theo cách thủ công, nhưng một lợi thế là khi tôi cập nhật nó, tôi có thể tiếp tục sao chép nó vào các máy chủ mới và không lo lắng về PATH trên một máy chủ mới được tạo với các thư mục không tồn tại ở đó.

##
## CON ĐƯỜNG
##
## Thay vì chỉ ghi đè PATH của chúng tôi với các thư mục có thể
## không phù hợp với máy chủ này, hãy cố gắng thông minh về những gì chúng tôi thêm
##
PATH = / usr / local / sbin: / usr / local / bin: / usr / sbin: / usr / bin: / sbin: / bin
[-d / cs / sbin] && PATH = / cs / sbin: $ PATH
[-d / cs / bin] && PATH = / cs / bin: $ PATH
[-d / usr / ucb] && PATH = $ PATH: / usr / ucb
[-d / usr / ccs / bin] && PATH = $ PATH: / usr / ccs / bin
[-d / usr / local / ssl / bin] && PATH = $ PATH: / usr / local / ssl / bin
[-d / usr / krb5 / bin] && PATH = $ PATH: / usr / krb5 / bin
[-d / usr / krb5 / sbin] && PATH = $ PATH: / usr / krb5 / sbin
[-d / usr / kerberos / sbin] && PATH = $ PATH: / usr / kerberos / sbin
[-d / usr / kerberos / bin] && PATH = $ PATH: / usr / kerberos / bin
[-d /cs/local/jdk1.5.0/bin] && PATH = $ PATH: /cs/local/jdk1.5.0/bin
[-d /usr/java/jre1.5.0_02/bin] && PATH = $ PATH: /usr/java/jre1.5.0_02/man
[-d /usr/java1.2/bin] && PATH = $ PATH: /usr/java1.2/bin
[-d /cs/local/perl5.8.0/bin] && PATH = $ PATH: /cs/local/perl5.8.0/bin
[-d / usr / perl5 / bin] && PATH = $ PATH: / usr / perl5 / bin
[-d / usr / X11R6 / bin] && PATH = $ PATH: / usr / X11R6 / bin
[-d / etc / X11] && PATH = $ PATH: / etc / X11
[-d / opt / sfw / bin] && PATH = $ PATH: / opt / sfw / bin
[-d / usr / local / apache / bin] && PATH = $ PATH: / usr / local / apache / bin
[-d / usr / apache / bin] && PATH = $ PATH: / usr / apache / bin
[-d / cs / admin / bin] && PATH = $ PATH: / cs / admin / bin
[-d / usr / openwin / bin] && PATH = $ PATH: / usr / openwin / bin
[-d / usr / xpg4 / bin] && PATH = $ PATH: / usr / xpg4 / bin
[-d / usr / dt / bin] && PATH = $ PATH: / usr / dt / bin

Tôi làm điều tương tự cho MANPATH của tôi:

##
## MANPATH
##
## Thay vì chỉ ghi đè MANPATH của chúng tôi với các thư mục có thể
## không phù hợp với máy chủ này, hãy cố gắng thông minh về những gì chúng tôi thêm
##
MANPATH = / usr / local / man
[-d / usr / share / man] && MANPATH = $ MANPATH: / usr / share / man
[-d / usr / local / share / man] && MANPATH = $ MANPATH: / usr / local / share / man
[-d / usr / man] && MANPATH = $ MANPATH: / usr / man
[-d / cs / man] && MANPATH = $ MANPATH: / cs / man
[-d / usr / krb5 / man] && MANPATH = $ MANPATH: / usr / krb5 / man
[-d / usr / kerberos / man] && MANPATH = $ MANPATH: / usr / kerberos / man
[-d / usr / local / ssl / man] && MANPATH = $ MANPATH: / usr / local / ssl / man
[-d /cs/local/jdk1.5.0/man] && MANPATH = $ MANPATH: /cs/local/jdk1.5.0/man
[-d /usr/java/jre1.5.0_02/man] && MANPATH = $ MANPATH: /usr/java/jre1.5.0_02/man
[-d /usr/java1.2/man] && MANPATH = $ MANPATH: /usr/java1.2/man
[-d / usr / X11R6 / man] && MANPATH = $ MANPATH: / usr / X11R6 / man
[-d / usr / local / apache / man] && MANPATH = $ MANPATH: / usr / local / apache / man
[-d / usr / local / mysql / man] && MANPATH = $ MANPATH: / usr / local / mysql / man
[-d /cs/local/perl5.8.0/man] && MANPATH = $ MANPATH: /cs/local/perl5.8.0/man
[-d / usr / perl5 / man] && MANPATH = $ MANPATH: / usr / perl5 / man
[-d / usr / local / perl / man] && MANPATH = $ MANPATH: / usr / local / perl / man
[-d /usr/local/perl5.8.0/man] && MANPATH = $ MANPATH: /usr/local/perl5.8.0/man
[-d / usr / openwin / man] && MANPATH = $ MANPATH: / usr / openwin / man

Ngoài việc có một tệp duy nhất mà tôi có thể sao chép vào các hệ thống trong các môi trường khác nhau mà không sợ thêm các thư mục không tồn tại vào PATH, phương pháp này cũng có ưu điểm là cho phép tôi chỉ định thứ tự tôi muốn các thư mục xuất hiện trong PATH. Vì dòng đầu tiên của mỗi định nghĩa xác định lại hoàn toàn biến PATH, tôi có thể cập nhật .bashrc của mình và lấy nguồn sau khi chỉnh sửa để cập nhật trình bao của mình mà không cần thêm các mục trùng lặp (mà tôi đã từng trải nghiệm từ lâu khi tôi đơn giản bắt đầu với " $ PATH = $ PATH: / new / dir ". Điều này đảm bảo tôi có được một bản sao sạch theo thứ tự tôi mong muốn.


1
đề xuất một giải pháp thay thế: d="/usr/share/man" ; [ -d "$d" ] && MANPATH="$MANPATH:${d}"Sẽ ngắn hơn và dễ dàng hơn để thêm một thư mục mới (chỉ cần sao chép một dòng và chỉnh sửa phần "d = ...." đầu tiên). Tuy nhiên, đối với PATH, tôi nghĩ rằng bạn sẽ kết thúc với quá nhiều dir trong PATH của mình, điều này không phải lúc nào cũng tốt (nếu một số lệnh "foo" tồn tại ở một trong những đường ít được biết đến và làm một điều gì đó hoàn toàn khác đó là những gì một người dùng thông thường mong đợi?)
Olivier Dulac

OP yêu cầu một cách ngắn gọn hơn để thêm đường dẫn. Điều này dài dòng hơn và dễ bị lỗi hơn những gì họ đã cố gắng tránh.
gạch dưới

-1

Có một cách dễ dàng! Đọc các hàm Shell và các biến đường dẫn tại Tạp chí Linux , ngày 01 tháng 3 năm 2000 bởi Stephen Collyer

Các hàm cho phép tôi sử dụng một kiểu dữ liệu mới trong môi trường bash của tôi - danh sách được phân tách bằng dấu hai chấm. Ngoài PATH, tôi sử dụng chúng để điều chỉnh LOCATE_PATH, MANPATH và các thứ khác, và như một kiểu dữ liệu chung trong lập trình bash. Đây là cách tôi thiết lập PATH của mình (sử dụng các chức năng):

# Add my bin directory to $PATH at the beginning, so it overrides 
addpath -f -p PATH $HOME/bin

# For Raspberry Pi development (add at end)
addpath -b -p PATH ${HOME}/rpi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin

# remove nonexistent directories from PATH
delpath -n -p PATH

# ensure PATH contains unique entries
uniqpath -p PATH

Vì liên kết Tạp chí Linux được gọi là "bị hỏng", tôi đã đặt Hàm Bash Path trong tệp .shar tại http://pastebin.ubuntu.com/13299528/


3
Những chức năng này là gì? OP sử dụng chúng như thế nào? Có lẽ chúng được mô tả trong liên kết bị hỏng trong câu trả lời của bạn, đó chính xác là lý do tại sao chúng tôi luôn muốn câu trả lời được khép kín. Vui lòng chỉnh sửa và bao gồm các chức năng thực tế trong câu trả lời của bạn.
terdon

@terdon: liên kết hoạt động với tôi, tôi đặt tệp .shar trên pastebin, tôi sẽ không đăng các dòng 1K ở đây.
waltinator

Rất tiếc, làm việc cho tôi quá bây giờ. Nó đã không khi tôi để lại nhận xét. Dù sao, ý chính của nhận xét của tôi là chúng tôi cố gắng tránh liên kết với các nguồn lực bên ngoài trong câu trả lời. Chúng tôi muốn thông tin ở đây , nơi nó có thể được cập nhật, chỉnh sửa và miễn nhiễm với mục đích liên kết.
terdon
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.