Bagaimana cara menambahkan path ke PATH dengan benar?

922

Saya bertanya-tanya di mana jalur baru harus ditambahkan ke PATHvariabel lingkungan. Saya tahu ini dapat dicapai dengan mengedit .bashrc(misalnya), tetapi tidak jelas bagaimana melakukan ini.

Cara ini:

export PATH=~/opt/bin:$PATH

atau ini?

export PATH=$PATH:~/opt/bin
Paolo
sumber
printf '\ nPATH = $ PATH: "path-to-add" \ nexport PATH \ n' >> ~ / .bashrc
Sudoer
Jika sudah ada beberapa jalur yang ditambahkan, misalnya PATH=$PATH:$HOME/.local/bin:$HOME/bin, jalur lain dapat ditambahkan dengan memisahkan dengan: misalnya PATH=$PATH:$HOME/.local/bin:$HOME/bin:/home/ec2-user/pear/bin.
Sandeepan Nath
2
Apakah jawaban ini berfungsi untuk semua rasa linux?
Ungeheuer

Jawaban:

1032

Hal-hal sederhana

PATH=$PATH:~/opt/bin

atau

PATH=~/opt/bin:$PATH

tergantung pada apakah Anda ingin menambahkan ~/opt/bindi akhir (akan dicari setelah semua direktori lain, jika ada program dengan nama yang sama di beberapa direktori) atau di awal (harus dicari sebelum semua direktori lain).

Anda dapat menambahkan beberapa entri sekaligus. PATH=$PATH:~/opt/bin:~/opt/node/binatau variasi pada pekerjaan pemesanan baik-baik saja. Jangan letakkan exportdi awal baris karena memiliki komplikasi tambahan (lihat di bawah "Catatan tentang cangkang selain bash").

Jika Anda PATHdibuat oleh banyak komponen berbeda, Anda mungkin berakhir dengan entri duplikat. Lihat Bagaimana cara menambahkan direktori home path untuk ditemukan oleh Unix perintah mana? dan Hapus entri $ PATH duplikat dengan perintah awk untuk menghindari menambahkan duplikat atau menghapusnya.

Beberapa distribusi secara otomatis dimasukkan ke ~/bindalam PATH Anda jika ada.

Di mana harus meletakkannya

Menempatkan baris untuk memodifikasi PATHdi ~/.profile, atau ~/.bash_profilejika itu yang Anda miliki.

Catatan yang ~/.bash_rctidak dibaca oleh program apa pun, dan ~/.bashrcmerupakan file konfigurasi instance interaktif bash. Anda seharusnya tidak mendefinisikan variabel lingkungan di ~/.bashrc. Tempat yang tepat untuk mendefinisikan variabel lingkungan seperti PATHadalah ~/.profile(atau ~/.bash_profilejika Anda tidak peduli dengan shell selain bash). Lihat Apa perbedaan antara mereka dan yang mana yang harus saya gunakan?

Jangan letakkan di /etc/environmentatau ~/.pam_environment: ini bukan file shell, Anda tidak dapat menggunakan substitusi seperti $PATHdi sana. Dalam file-file ini, Anda hanya bisa menimpa variabel, bukan menambahkannya.

Potensi komplikasi dalam beberapa skrip sistem

Anda tidak perlu exportjika variabel sudah ada di lingkungan: setiap perubahan nilai variabel tercermin di lingkungan. PATHPretty hampir selalu ada di lingkungan; semua sistem unix mengaturnya sangat awal (biasanya pada proses pertama, sebenarnya).

Pada saat login, Anda dapat mengandalkan PATHyang sudah ada di lingkungan, dan sudah mengandung beberapa direktori sistem. Jika Anda menulis skrip yang dapat dijalankan lebih awal saat menyiapkan beberapa jenis lingkungan virtual, Anda mungkin perlu memastikan bahwa PATHitu tidak kosong dan diekspor: jika PATHmasih tidak disetel, maka sesuatu seperti PATH=$PATH:/some/directoryakan diatur PATHke :/some/directory, dan komponen kosong di awal berarti direktori saat ini (seperti .:/some/directory).

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

Catatan tentang kerang selain bash

Di bash, ksh dan zsh, exportadalah sintaks khusus, dan kedua PATH=~/opt/bin:$PATHdan export PATH=~/opt/bin:$PATHmelakukan hal yang benar bahkan. Dalam shell Bourne / POSIX-style lainnya seperti dash (yang ada /bin/shdi banyak sistem), exportdiurai sebagai perintah biasa, yang menyiratkan dua perbedaan:

Jadi di shell seperti dash, export PATH=~/opt/bin:$PATHset PATHke string literal ~/opt/bin/:diikuti oleh nilai PATHhingga ruang pertama. PATH=~/opt/bin:$PATH(tugas kosong) tidak memerlukan penawaran dan melakukan hal yang benar. Jika Anda ingin menggunakan exportskrip portabel, Anda harus menulis export PATH="$HOME/opt/bin:$PATH", atau PATH=~/opt/bin:$PATH; export PATH(atau PATH=$HOME/opt/bin:$PATH; export PATHagar mudah dibawa ke shell Bourne yang tidak menerima export var=valuedan tidak melakukan ekspansi tilde).

¹ Ini tidak benar pada cangkang Bourne (seperti pada cangkang Bourne yang sebenarnya, bukan cangkang bergaya POSIX modern), tetapi Anda sangat tidak mungkin menemukan cangkang-cangkang tua seperti itu belakangan ini.

Gilles
sumber
Masih belum bisa memahami komplikasi dengan ekspor. bisakah Anda menyederhanakannya?
priojeet priyom
@priojeetpriyom Penjelasan sederhana: Anda tidak perlu export.
Gilles
Terima kasih atas jawaban ini, sangat detail. Anda mengatakan " Anda seharusnya tidak mendefinisikan variabel lingkungan di ~ / .bashrc ", tetapi sayangnya 100% dari program yang saya instal di sistem saya yang memodifikasi jalur (FZF dan Rust's Cargo) memodifikasi jalur di .bashrc. Saya berasumsi karena FZF ditulis dalam Rust juga mengikuti pola Rust.
icc97
83

Either way bekerja, tetapi mereka tidak melakukan hal yang sama: elemen PATHdiperiksa dari kiri ke kanan. Dalam contoh pertama Anda, executable di ~/opt/binakan lebih diutamakan daripada yang diinstal, misalnya, di /usr/bin, yang mungkin atau mungkin tidak seperti yang Anda inginkan.

Secara khusus, dari sudut pandang keamanan, berbahaya untuk menambahkan jalur ke depan, karena jika seseorang dapat memperoleh akses tulis ke Anda ~/opt/bin, mereka dapat menempatkan, misalnya, perbedaan lsdi sana, yang mungkin akan Anda gunakan sebagai gantinya dari /bin/lstanpa memperhatikan. Sekarang bayangkan hal yang sama untuk sshatau browser atau pilihan Anda ... (Hal yang sama berlaku untuk menempatkan. Di jalur Anda.)

Ulrich Schwarz
sumber
6
Tetapi jika Anda ingin memiliki versi Anda sendiri yang telah disesuaikan ls, Anda harus meletakkannya di direktori sebelumnya /bin.
Barmar
16
atau alias ls = myls
waltinator
37

Saya bingung dengan pertanyaan 2 (sejak dihapus dari pertanyaan karena masalah yang tidak terkait):

Apa cara yang bisa dilakukan untuk menambahkan lebih banyak jalur pada jalur yang berbeda? Awalnya saya pikir ini bisa melakukan trik:

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

tetapi itu bukan karena tugas kedua tidak hanya menambahkan ~/opt/node/bin, tetapi juga keseluruhan PATHditugaskan sebelumnya.

Ini adalah solusi yang mungkin:

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

tetapi untuk keterbacaan saya lebih suka memiliki satu tugas untuk satu jalur.

Jika Anda mengatakan

PATH=~/opt/bin

itu saja yang ada di PATH Anda. PATH hanyalah variabel lingkungan, dan jika Anda ingin menambahkan ke PATH, Anda harus membangun kembali variabel dengan konten yang Anda inginkan. Artinya, apa yang Anda berikan sebagai contoh untuk pertanyaan 2 adalah persis apa yang ingin Anda lakukan, kecuali saya benar-benar kehilangan inti pertanyaan.

Saya menggunakan kedua formulir dalam kode saya. Saya memiliki profil umum yang saya instal pada setiap mesin yang saya kerjakan yang terlihat seperti ini, untuk mengakomodasi direktori yang berpotensi hilang:

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
Carl Cravens
sumber
2
Anda benar tentang contoh pertanyaan 2, ini berhasil. Masalah terkait PATH lainnya pada sistem saya membingungkan saya. Maaf untuk itu.
Paolo
26

Cara tahan peluru dari Appending / Prepending

Ada banyak pertimbangan yang terlibat dalam pilihan penambahan versus prepending. Banyak dari mereka tercakup dalam jawaban lain, jadi saya tidak akan mengulanginya di sini.

Poin penting adalah bahwa, bahkan jika skrip sistem tidak menggunakan ini (saya bertanya-tanya mengapa) * 1 , cara anti peluru untuk menambahkan path (misalnya, $HOME/bin) ke variabel lingkungan PATH adalah

PATH="${PATH:+${PATH}:}$HOME/bin"

untuk menambahkan (bukan PATH="$PATH:$HOME/bin") dan

PATH="$HOME/bin${PATH:+:${PATH}}"

untuk prepending (bukan PATH="$HOME/bin:$PATH")

Hal ini menghindari kolon leading / trailing palsu ketika $PATHawalnya kosong, yang dapat memiliki efek samping yang tidak diinginkan dan dapat menjadi mimpi buruk , sulit ditemukan ( jawaban ini secara singkat berkaitan dengan case awk- the - the way).

Penjelasan (dari Ekspansi Parameter Shell ):

${parameter:+word}

Jika parameternol atau tidak disetel, tidak ada yang diganti, jika tidak maka ekspansi wordakan diganti.

Dengan demikian, ${PATH:+${PATH}:}diperluas ke: 1) tidak ada, jika PATHnol atau tidak disetel, 2) ${PATH}:, jika PATHdiatur.

Catatan : Ini untuk bash.


* 1 Saya baru saja menemukan bahwa skrip seperti devtoolset-6/enablebenar - benar menggunakan ini,

$ cat /opt/rh/devtoolset-6/enable
# General environment variables
export PATH=/opt/rh/devtoolset-6/root/usr/bin${PATH:+:${PATH}}
...
sancho.s
sumber
24

Linux menentukan jalur pencarian yang dapat dieksekusi dengan $PATHvariabel lingkungan. Untuk menambahkan direktori / data / myscripts ke awal $PATHvariabel lingkungan, gunakan yang berikut ini:

PATH=/data/myscripts:$PATH

Untuk menambahkan direktori itu ke ujung jalan, gunakan perintah berikut:

PATH=$PATH:/data/myscripts

Tetapi sebelumnya tidak cukup karena ketika Anda menetapkan variabel lingkungan di dalam skrip, perubahan itu hanya efektif dalam skrip. Hanya ada dua cara untuk mengatasi batasan ini:

  • Jika dalam skrip, Anda mengekspor variabel lingkungan, itu efektif dalam setiap program yang dipanggil oleh skrip. Perhatikan bahwa itu tidak efektif dalam program yang disebut skrip.
  • Jika program yang memanggil skrip melakukannya dengan memasukkan alih-alih memanggil, perubahan lingkungan apa pun dalam skrip akan efektif dalam program panggilan. Inklusi seperti itu dapat dilakukan dengan perintah titik atau perintah sumber.

Contoh:

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

Inklusi pada dasarnya menggabungkan skrip "dipanggil" dalam skrip "panggil". Ini seperti #include dalam C. Jadi itu efektif di dalam skrip atau program "calling". Tetapi tentu saja, itu tidak efektif dalam program atau skrip apa pun yang dipanggil oleh program panggilan. Untuk membuatnya efektif sepanjang rantai panggilan, Anda harus mengikuti pengaturan variabel lingkungan dengan perintah ekspor.

Sebagai contoh, program bash shell menggabungkan konten file .bash_profile dengan penyertaan. Tempatkan 2 baris berikut di .bash_profile:

PATH=$PATH:/data/myscripts
export PATH

secara efektif menempatkan 2 baris kode tersebut dalam program bash. Jadi dalam bash, variabel $ PATH termasuk $HOME/myscript.sh, dan karena pernyataan ekspor, setiap program yang dipanggil oleh bash memiliki $PATHvariabel yang diubah . Dan karena setiap program yang Anda jalankan dari bash prompt dipanggil oleh bash, jalur baru ini berlaku untuk apa pun yang Anda jalankan dari bash prompt.

Intinya adalah bahwa untuk menambahkan direktori baru ke path, Anda harus menambahkan atau menambahkan direktori ke variabel lingkungan $ PATH dalam skrip yang termasuk dalam shell, dan Anda harus mengekspor $PATHvariabel lingkungan.

Informasi lebih lanjut di sini

Steve Brown
sumber
19

Untuk beberapa waktu sekarang saya telah menyimpan dua fungsi pathadddan pathrmyang membantu dalam menambahkan elemen ke jalan tanpa perlu khawatir tentang duplikasi.

pathaddmengambil argumen jalur tunggal dan argumen opsional afteryang jika disediakan akan ditambahkan ke yang PATHsebaliknya.

Di hampir setiap situasi jika Anda menambahkan ke jalur maka Anda cenderung ingin menimpa apa pun yang sudah ada di jalur, itulah sebabnya saya memilih untuk menambahkan sebelumnya secara default.

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')"
}

Letakkan ini di skrip yang ingin Anda ubah lingkungan PATH dan sekarang bisa Anda lakukan.

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

Anda dijamin tidak menambahkan ke jalur jika sudah ada. Jika sekarang Anda ingin memastikan /baz/batsudah di awal.

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

Sekarang setiap jalur dapat dipindahkan ke depan jika sudah ada di jalur tanpa menggandakan.

Brett Ryan
sumber
Pendekatan terkait dan lebih bersih untuk memeriksa keberadaan direktori di PATH Anda: unix.stackexchange.com/a/32054/135943
Wildcard
9

Saya tidak dapat berbicara untuk distribusi lain, tetapi Ubuntu memiliki file, / etc / environment, yang merupakan jalur pencarian default untuk semua pengguna. Karena komputer saya hanya digunakan oleh saya, saya meletakkan direktori yang saya inginkan di jalur saya di sana, kecuali itu adalah tambahan sementara yang saya masukkan ke dalam skrip.

Jim Bradley
sumber
6

Ada beberapa situasi di mana penggunaannya PATH=/a/b:$PATHmungkin dianggap sebagai cara "salah" untuk menambahkan jalur ke PATH:

  1. Menambahkan jalur yang sebenarnya bukan direktori.
  2. Menambahkan jalur yang sudah ada dalam PATHbentuk yang sama.
  3. Menambahkan jalur relatif (karena direktori aktual yang dicari akan berubah ketika Anda mengubah direktori kerja saat ini).
  4. Menambahkan jalur yang sudah ada di PATHdalam bentuk yang berbeda (yaitu alias karena menggunakan symlinks atau ..).
  5. Jika Anda menghindari melakukan 4, tidak memindahkan jalur ke depan PATHketika itu dimaksudkan untuk menimpa entri lain di PATH.

Fungsi (khusus Bash) ini melakukan "hal yang benar" dalam situasi di atas (dengan pengecualian, lihat di bawah), mengembalikan kode kesalahan, dan mencetak pesan yang bagus untuk manusia. Kode dan pesan kesalahan dapat dinonaktifkan ketika tidak diinginkan.

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"
}

Pengecualiannya adalah bahwa fungsi ini tidak mengkanonik lintasan yang ditambahkan PATHmelalui cara lain, jadi jika alias non-kanonik untuk lintasan ada PATH, ini akan menambah duplikat. Mencoba untuk meng-kanonikkan path yang sudah ada PATHadalah proposisi yang tidak pasti karena path relatif memiliki makna yang jelas ketika diteruskan ke prepathtetapi ketika sudah di path Anda tidak tahu apa direktori kerja saat ini ketika ditambahkan.

Curt J. Sampson
sumber
mengenai jalur relatif: bagaimana dengan memiliki sakelar '-r', yang akan menambahkan jalur tanpa menjadikannya absolut terlebih dahulu, dan yang juga akan melihatnya sebagai absolut sebelum menambahkannya? Jika ini adalah skrip, seseorang dapat menggunakannya di shell lain. Apakah ada manfaat memiliki fungsi? kode yang bagus!
hoijui
1
@hoijui Itu harus berfungsi karena memodifikasi lingkungan saat ini. Jika itu adalah skrip, itu akan mengubah lingkungan subproses menjalankan skrip dan, ketika skrip keluar Anda akan memiliki yang sama $PATHseperti sebelumnya. Adapun -r, tidak, saya pikir jalur relatif di $PATHterlalu tidak dapat diandalkan dan aneh (jalur Anda berubah setiap kali Anda cd!) Ingin mendukung sesuatu seperti itu di alat umum.
Curt J. Sampson
5

Bagi saya (di Mac OS X 10.9.5), menambahkan nama jalur (mis. /mypathname) Ke file /etc/pathsbekerja dengan sangat baik.

Sebelum mengedit, echo $PATHmengembalikan:

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

Setelah mengedit /etc/pathsdan memulai kembali shell, variabel $ PATH ditambahkan /pathname. Memang, echo $PATHpengembalian:

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

Apa yang terjadi adalah yang /mypathnametelah ditambahkan ke $PATHvariabel.

faelx
sumber
3
Lebih baik menambahkan file ke direktori /etc/paths.d daripada mengedit file / etc / paths itu sendiri.
rbrewer
4

Untuk menambahkan jalur baru ke PATHvariabel lingkungan:

export PATH=$PATH:/new-path/

Untuk perubahan ini harus diterapkan pada setiap shell Anda membuka, tambahkan ke file yang shell akan sumber ketika dipanggil. Dalam cangkang yang berbeda ini dapat:

  • Bash Shell: ~ / .bash_profile, ~ / .bashrc atau profil
  • Korn Shell: ~ / .kshrc atau .profile
  • Z Shell: ~ / .zshrc atau .zprofile

misalnya

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

Anda dapat melihat jalur yang disediakan di output di atas.

Amit24x7
sumber
4

Ini solusinya:

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

Satu liner mudah dan menyenangkan yang tidak meninggalkan jejak :

AJ.
sumber
1
-bash: awk: Tidak ada file atau direktori tersebut -bash: sed: Tidak ada file atau direktori seperti itu
davidcondrey
1
@davidcondrey - awk dan sed adalah perintah eksternal yang sangat umum. Jawaban ini memberikan cara murni-bash untuk mencapai hal yang sama, sehingga bekerja bahkan dalam kasus ketika awk dan / atau sed tidak ada (atau direktori masing-masing tidak ada di jalur!)
sancho.s