it-swarm-vi.com

Làm thế nào để thêm chính xác một đường dẫn đến PATH?

Tôi đang tự hỏi nơi một đường dẫn mới phải được thêm vào biến môi trường PATH. Tôi biết điều này có thể được thực hiện bằng cách chỉnh sửa .bashrc (ví dụ), nhưng không rõ làm thế nào để làm điều này.

Cách này:

export PATH=~/opt/bin:$PATH

hay cái này

export PATH=$PATH:~/opt/bin
994
Paolo

Những thứ đơn giản

PATH=$PATH:~/opt/bin

hoặc là

PATH=~/opt/bin:$PATH

tùy thuộc vào việc bạn muốn thêm ~/opt/bin ở cuối (được tìm kiếm sau tất cả các thư mục khác, trong trường hợp có một chương trình có cùng tên trong nhiều thư mục) hoặc ở đầu (được tìm kiếm trước tất cả các thư mục khác).

Bạn có thể thêm nhiều mục cùng một lúc. PATH=$PATH:~/opt/bin:~/opt/node/bin hoặc các biến thể của công việc đặt hàng tốt. Đừng đặt export ở đầu dòng vì nó có các biến chứng bổ sung (xem bên dưới phần Ghi chú trên vỏ ngoài các bash khác).

Nếu PATH của bạn được xây dựng bởi nhiều thành phần khác nhau, bạn có thể sẽ có các mục trùng lặp. Xem Cách thêm đường dẫn thư mục chính được phát hiện bởi lệnh Unix nào?Xóa các mục nhập $ PATH trùng lặp bằng lệnh awk để tránh thêm trùng lặp hoặc xóa chúng.

Một số bản phân phối tự động đặt ~/bin trong PATH của bạn nếu nó tồn tại, nhân tiện.

Đặt nó ở đâu

Đặt dòng để sửa đổi PATH in ~/.profile hoặc trong ~/.bash_profile nếu đó là những gì bạn có.

Lưu ý rằng ~/.bash_rc không được đọc bởi bất kỳ chương trình nào và ~/.bashrc là tệp cấu hình của các phiên bản tương tác của bash. Bạn không nên xác định các biến môi trường trong ~/.bashrc. Vị trí thích hợp để xác định các biến môi trường, chẳng hạn như PATH~/.profile (hoặc là ~/.bash_profile nếu bạn không quan tâm đến các vỏ khác ngoài bash). Xem Sự khác biệt giữa chúng và tôi nên sử dụng cái nào?

Đừng đặt nó vào /etc/environment hoặc là ~/.pam_environment: đây không phải là các tệp Shell, bạn không thể sử dụng các thay thế như $PATH trong đó. Trong các tệp này, bạn chỉ có thể ghi đè một biến, không thêm vào nó.

Biến chứng tiềm ẩn trong một số tập lệnh hệ thống

Bạn không cần export nếu biến đã có trong môi trường: mọi thay đổi của giá trị của biến được phản ánh trong môi trường.¹ PATH luôn luôn tồn tại trong môi trường; tất cả các hệ thống unix thiết lập nó rất sớm (thường là trong quá trình đầu tiên, trên thực tế).

Tại thời điểm đăng nhập, bạn có thể dựa vào PATH đang ở trong môi trường và đã chứa một số thư mục hệ thống. Nếu bạn đang viết một tập lệnh có thể được thực thi sớm trong khi thiết lập một loại môi trường ảo nào đó, bạn có thể cần đảm bảo rằng PATH không trống và được xuất: nếu PATH vẫn chưa được đặt , sau đó một cái gì đó như PATH=$PATH:/some/directory sẽ đặt PATH thành :/some/directory và thành phần trống ở đầu có nghĩa là thư mục hiện tại (như .:/some/directory).

if [ -z "${PATH-}" ]; then export PATH=/usr/local/bin:/usr/bin:/bin; fi

Ghi chú về vỏ khác với bash

Trong bash, ksh và zsh, export là cú pháp đặc biệt và cả PATH=~/opt/bin:$PATHexport PATH=~/opt/bin:$PATH làm điều đúng ngay cả. Trong các shell kiểu Bourne/POSIX khác, chẳng hạn như dấu gạch ngang (đó là /bin/sh trên nhiều hệ thống), export được phân tích cú pháp như một lệnh thông thường, hàm ý hai điểm khác biệt:

Vì vậy, trong vỏ như dấu gạch ngang, export PATH=~/opt/bin:$PATH đặt PATH thành chuỗi ký tự ~/opt/bin/: theo sau là giá trị của PATH cho đến khoảng trắng đầu tiên. PATH=~/opt/bin:$PATH (một bài tập trần) không yêu cầu dấu ngoặc kép và thực hiện đúng. Nếu bạn muốn sử dụng export trong tập lệnh di động, bạn cần viết export PATH="$HOME/opt/bin:$PATH", hoặc là PATH=~/opt/bin:$PATH; export PATH (hoặc là PATH=$HOME/opt/bin:$PATH; export PATH về tính di động đối với ngay cả Bourne Shell không chấp nhận export var=value và không làm mở rộng dấu ngã).

¹ Điều này không đúng trong các vỏ Bourne (như trong Bourne Shell thực tế, không phải là các vỏ kiểu POSIX hiện đại), nhưng bạn rất khó gặp phải các vỏ cũ như vậy ngày nay.

1114

Dù bằng cách nào, nhưng chúng không làm điều tương tự: các yếu tố của PATH được kiểm tra từ trái sang phải. Trong ví dụ đầu tiên của bạn, các tệp thực thi trong ~/opt/bin sẽ được ưu tiên hơn các cài đặt, ví dụ, trong /usr/bin, có thể hoặc không thể là thứ bạn muốn.

Cụ thể, từ quan điểm an toàn, sẽ rất nguy hiểm khi thêm đường dẫn vào phía trước, bởi vì nếu ai đó có thể có quyền truy cập ghi vào ~/opt/bin của bạn, ví dụ, họ có thể đặt ls khác trong đó, mà sau đó bạn có thể sử dụng thay vì /bin/ls mà không nhận thấy. Bây giờ hãy tưởng tượng tương tự cho ssh hoặc trình duyệt hoặc lựa chọn của bạn ... (Điều tương tự cũng xảy ra khi đặt. Trong đường dẫn của bạn.)

88
Ulrich Schwarz

Tôi bối rối bởi câu hỏi 2 (vì đã bị xóa khỏi câu hỏi vì đó là do một vấn đề không liên quan):

Cách nào khả thi để nối thêm đường dẫn trên các dòng khác nhau? Ban đầu tôi nghĩ rằng điều này có thể thực hiện các mẹo:

export PATH=$PATH:~/opt/bin
export PATH=$PATH:~/opt/node/bin

nhưng không phải vì bài tập thứ hai không chỉ nối thêm ~/opt/node/bin, nhưng cũng là toàn bộ PATH được gán trước đó.

Đây là một cách giải quyết có thể:

export PATH=$PATH:~/opt/bin:~/opt/node/bin

nhưng để dễ đọc, tôi muốn có một nhiệm vụ cho một đường dẫn.

Nếu bạn nói

PATH=~/opt/bin

đó là tất cả đó sẽ nằm trong ĐƯỜNG của bạn. PATH chỉ là một biến môi trường và nếu bạn muốn thêm vào PATH, bạn phải xây dựng lại biến với chính xác nội dung bạn muốn. Đó là, những gì bạn đưa ra làm ví dụ cho câu hỏi 2 chính xác là những gì bạn muốn làm, trừ khi tôi hoàn toàn thiếu quan điểm của câu hỏi.

Tôi sử dụng cả hai hình thức trong mã của tôi. Tôi có một hồ sơ chung mà tôi cài đặt trên mọi máy tôi làm việc trông giống như thế này, để phù hợp với các thư mục có khả năng bị thiếu:

export PATH=/opt/bin:/usr/local/bin:/usr/contrib/bin:/bin:/usr/bin:/usr/sbin:/usr/bin/X11
# add optional items to the path
for bindir in $HOME/local/bin $HOME/bin; do
    if [ -d $bindir ]; then
        PATH=$PATH:${bindir}
    fi
done
39
Carl Cravens

Linux xác định đường dẫn tìm kiếm thực thi với $PATH biến môi trường. Để thêm thư mục/dữ liệu/myscripts vào đầu $PATH biến môi trường, sử dụng như sau:

PATH=/data/myscripts:$PATH

Để thêm thư mục đó vào cuối đường dẫn, sử dụng lệnh sau:

PATH=$PATH:/data/myscripts

Nhưng điều trước là không đủ vì khi bạn đặt biến môi trường bên trong tập lệnh, thay đổi đó chỉ có hiệu lực trong tập lệnh. Chỉ có hai cách xung quanh giới hạn này:

  • Nếu trong tập lệnh, bạn xuất biến môi trường thì nó có hiệu lực trong bất kỳ chương trình nào được gọi bởi tập lệnh. Lưu ý rằng nó không hiệu quả trong chương trình được gọi là script.
  • Nếu chương trình gọi tập lệnh thực hiện bằng cách đưa vào thay vì gọi, bất kỳ thay đổi môi trường nào trong tập lệnh đều có hiệu lực trong chương trình gọi. Việc đưa vào như vậy có thể được thực hiện bằng lệnh dot hoặc lệnh nguồn.

Ví dụ:

$HOME/myscript.sh
source $HOME/myscript.sh

Về cơ bản, việc kết hợp kịch bản "được gọi" trong tập lệnh "gọi". Nó giống như một #incoide trong C. Vì vậy, nó có hiệu quả trong tập lệnh hoặc chương trình "gọi". Nhưng tất nhiên, nó không hiệu quả trong bất kỳ chương trình hoặc tập lệnh nào được gọi bởi chương trình gọi. Để làm cho nó hiệu quả trong suốt chuỗi cuộc gọi, bạn phải tuân theo cài đặt của biến môi trường bằng lệnh xuất.

Ví dụ, chương trình bash Shell kết hợp nội dung của tệp .bash_profile bằng cách đưa vào. Đặt 2 dòng sau vào .bash_profile:

PATH=$PATH:/data/myscripts
export PATH

có hiệu quả đặt 2 dòng mã đó trong chương trình bash. Vì vậy, trong bash, biến $ PATH bao gồm $HOME/myscript.sh và vì câu lệnh xuất, bất kỳ chương trình nào được gọi bởi bash đều bị thay đổi $PATH Biến đổi. Và bởi vì bất kỳ chương trình nào bạn chạy từ bash Prompt đều được gọi bằng bash, đường dẫn mới có hiệu lực cho mọi thứ bạn chạy từ bash Prompt.

Điểm mấu chốt là để thêm một thư mục mới vào đường dẫn, bạn phải nối hoặc thêm thư mục vào biến môi trường $ PATH trong tập lệnh có trong Shell và bạn phải xuất $PATH biến môi trường.

Thêm thông tin tại đây

25
Steve Brown

Lâu nay tôi đã giữ cho tôi hai hàm pathaddpathrm hỗ trợ thêm các phần tử vào đường dẫn mà không cần phải lo lắng về việc sao chép.

pathadd nhận một đối số đường dẫn duy nhất và một đối số after tùy chọn mà nếu được cung cấp sẽ nối với PATH nếu không, nó sẽ bổ sung cho nó.

Trong hầu hết mọi tình huống nếu bạn thêm vào đường dẫn thì có khả năng bạn muốn ghi đè mọi thứ đã có trong đường dẫn, đó là lý do tại sao tôi chọn không trả trước theo mặc định.

pathadd() {
    newelement=${1%/}
    if [ -d "$1" ] && ! echo $PATH | grep -E -q "(^|:)$newelement($|:)" ; then
        if [ "$2" = "after" ] ; then
            PATH="$PATH:$newelement"
        else
            PATH="$newelement:$PATH"
        fi
    fi
}

pathrm() {
    PATH="$(echo $PATH | sed -e "s;\(^\|:\)${1%/}\(:\|\$\);\1\2;g" -e 's;^:\|:$;;g' -e 's;::;:;g')"
}

Đặt chúng trong bất kỳ tập lệnh nào bạn muốn thay đổi môi trường PATH và bây giờ bạn có thể làm.

pathadd "/foo/bar"
pathadd "/baz/bat" after
export PATH

Bạn được đảm bảo không thêm vào đường dẫn nếu nó đã ở đó. Nếu bây giờ bạn muốn đảm bảo /baz/bat là lúc bắt đầu.

pathrm "/baz/bat"
pathadd "/baz/bat"
export PATH

Bây giờ bất kỳ đường dẫn nào cũng có thể được di chuyển ra phía trước nếu nó đã ở trong đường dẫn mà không cần nhân đôi.

20
Brett Ryan

Tôi không thể nói cho các bản phân phối khác, nhưng Ubuntu có một tệp,/etc/môi trường, đó là đường dẫn tìm kiếm mặc định cho tất cả người dùng. Vì máy tính của tôi chỉ được tôi sử dụng, tôi đặt bất kỳ thư mục nào tôi muốn trong đường dẫn của mình ở đó, trừ khi đó là một bổ sung tạm thời mà tôi đặt trong một tập lệnh.

10
Jim Bradley

Có một số tình huống sử dụng PATH=/a/b:$PATH có thể được coi là cách "không chính xác" để thêm đường dẫn vào PATH:

  1. Thêm một đường dẫn không thực sự là một thư mục.
  2. Thêm một đường dẫn đã có trong PATH ở dạng tương tự.
  3. Thêm một đường dẫn tương đối (vì thư mục thực tế được tìm kiếm sẽ thay đổi khi bạn thay đổi thư mục làm việc hiện tại).
  4. Thêm một đường dẫn đã có trong PATH ở dạng khác (nghĩa là bí danh do sử dụng liên kết tượng trưng hoặc ..).
  5. Nếu bạn tránh thực hiện 4, không di chuyển đường dẫn đến phía trước PATH khi dự định ghi đè các mục khác trong PATH.

Hàm này (chỉ dành cho Bash) thực hiện "điều đúng" trong các tình huống trên (với một ngoại lệ, xem bên dưới), trả về mã lỗi và in thông điệp Nice cho con người. Mã lỗi và thông báo có thể bị vô hiệu hóa khi chúng không muốn.

prepath() {
    local usage="\
Usage: prepath [-f] [-n] [-q] DIR
  -f Force dir to front of path even if already in path
  -n Nonexistent dirs do not return error status
  -q Quiet mode"

    local tofront=false errcode=1 qecho=echo
    while true; do case "$1" in
        -f)     tofront=true;       shift;;
        -n)     errcode=0;          shift;;
        -q)     qecho=':';          shift;;
        *)      break;;
    esac; done
    # Bad params always produce message and error code
    [[ -z $1 ]] && { echo 1>&2 "$usage"; return 1; }

    [[ -d $1 ]] || { $qecho 1>&2 "$1 is not a directory."; return $errcode; }
    dir="$(command cd "$1"; pwd -P)"
    if [[ :$PATH: =~ :$dir: ]]; then
        $tofront || { $qecho 1>&2 "$dir already in path."; return 0; }
        PATH="${PATH#$dir:}"        # remove if at start
        PATH="${PATH%:$dir}"        # remove if at end
        PATH="${PATH//:$dir:/:}"    # remove if in middle
    fi
    PATH="$dir:$PATH"
}

Ngoại lệ là hàm này không hợp quy hóa các đường dẫn được thêm vào PATH thông qua các phương tiện khác, vì vậy nếu bí danh không chính tắc cho một đường dẫn nằm trong PATH, thì điều này sẽ thêm một bản sao. Cố gắng chuẩn hóa các đường dẫn đã có trong PATH là một đề xuất khó khăn vì một đường dẫn tương đối có ý nghĩa rõ ràng khi được chuyển đến prepath nhưng khi đã ở trong đường dẫn, bạn không biết thư mục làm việc hiện tại là gì khi nó được thêm vào.

7
cjs

Để thêm một đường dẫn mới vào biến môi trường PATH:

export PATH=$PATH:/new-path/

Để thay đổi này được áp dụng cho mọi Shell bạn mở, hãy thêm nó vào tệp mà Shell sẽ nguồn khi nó được gọi. Trong các shell khác nhau, điều này có thể là:

  • Bash Shell: ~/.bash_profile, ~/.bashrc hoặc hồ sơ
  • Korn Shell: ~/.kshrc hoặc .profile
  • Vỏ Z: ~/.zshrc hoặc .zprofile

ví dụ.

# export PATH=$PATH:/root/learning/bin/
# source ~/.bashrc
# echo $PATH

Bạn có thể thấy đường dẫn được cung cấp trong đầu ra ở trên.

7
Amit24x7

Đối với tôi (trên Mac OS X 10.9.5), thêm tên đường dẫn (ví dụ: /mypathname) vào tệp /etc/paths làm việc rất tốt.

Trước khi chỉnh sửa, echo $PATH trả về:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin

Sau khi chỉnh sửa /etc/paths và khởi động lại Shell, biến $ PATH được nối với /pathname. Thật, echo $PATH trả về:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/mypathname

Điều gì đã xảy ra là /mypathname đã được thêm vào $PATH Biến đổi.

6
faelx

Đây là giải pháp của tôi:

PATH=$(echo -n $PATH | awk -v RS=: -v ORS=: '!x[$0]++' | sed "s/\(.*\).\{1\}/\1/")

Một lớp lót dễ dàng đẹp mà không để lại dấu vết :

5
AJ.