Cara yang lebih nyaman untuk mengedit $ PATH yang panjang?

35

Saya ingin menambahkan, di ~ / .bashrc, beberapa direktori ke $ PATH saya.

$ PATH saya cukup panjang sehingga agak sulit untuk melihat direktori apa yang dikandungnya dan dalam urutan apa.

Saya tahu saya bisa memodifikasi ~ / .bashrc saya menjadi:

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

itu akan membuatnya lebih mudah untuk dibaca. Tapi saya bertanya-tanya apakah selama tahun-tahun terakhir Bash telah memperoleh beberapa sintaks yang membuat menentukan PATH panjang lebih mudah. Misalnya, saya berfantasi tentang sintaksis yang mirip dengan:

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

Saya tahu sintaks seperti itu tidak valid. Saya bertanya-tanya apakah ada sesuatu yang mudah. Disana?

Niccolo M.
sumber
Tutorial tradisional untuk mengatur jalur melalui PATH=foo:$PATHtampaknya salah karena terus tumbuh setiap saat source ~/.bashrcdan bahkan exec bashtidak dapat membantu sejak $PATHitu export.
林果 皞

Jawaban:

25

Saya menggunakan satu set fungsi kenyamanan untuk menambahkan atau menambahkan path ke variabel. Fungsi datang dalam tarball distribusi untuk Bash dalam file contrib yang disebut "pathfuncs".

  • add_path akan menambahkan entri ke akhir variabel PATH
  • pre_path akan menambahkan entri ke awal variabel PATH
  • del_path akan menghapus entri dari variabel PATH, di mana pun itu

Jika Anda menentukan variabel sebagai argumen kedua, ia akan menggunakannya sebagai ganti PATH.

Untuk kenyamanan, inilah mereka:

# 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;:\$;;"`
}

Jika Anda menambahkannya ke file startup bash Anda, Anda dapat menambahkan ke PATH Anda seperti ini:

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

Atau tentukan variabel yang berbeda:

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

Saya menggunakan metode ini dalam file rc saya dengan menempatkan pre_paths pertama dan add_paths kedua. Itu membuat semua perubahan jalur saya mudah dimengerti sekilas. Manfaat lain adalah bahwa garis-garisnya cukup pendek sehingga saya dapat menambahkan komentar tambahan pada sebuah baris jika perlu.

Dan karena ini adalah fungsi, Anda dapat menggunakannya secara interaktif dari baris perintah, seperti dengan mengatakan add_path $(pwd)untuk menambahkan direktori saat ini ke path.

Bintang laut
sumber
Terima kasih. Saya telah memeriksa kode Anda dan berfungsi. Anehnya, saya juga menemukan kegunaan untuk del_path (A "." Masuk ke PATH saya dalam beberapa situasi, iblis tahu dari mana, jadi saya melakukannya del_path .).
Niccolo M.
Hai. dimungkinkan untuk sumber (termasuk) pathfuncs ini dari skrip bashrc atau haruskah saya menyalin / menempelkannya ke sana?
Cristiano
@Cristiano Baik akan bekerja. Itu benar-benar terserah Anda.
Bintang laut
11

OK, saya menemukan solusi berikut, yang menurut saya elegan (sejauh sintaksis shell pergi). Ini menggunakan sintaks array Bash dan juga cara yang rapi untuk bergabung dengan elemen:

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

WASPADA!

Ternyata solusi ini memiliki masalah : Berbeda dengan solusi @terdon dan @Starfish, itu tidak memeriksa terlebih dahulu apakah jalur sudah di PATH. Jadi, karena saya ingin meletakkan kode ini di ~ / .bashrc (dan bukan di ~ / .profile), jalur duplikat akan menyusup ke PATH. Jadi jangan gunakan solusi ini (kecuali Anda memasukkannya di ~ / .profile (atau, lebih baik, ~ / .bash_profile karena memiliki sintaks spesifik Bash)).

Niccolo M.
sumber
1
Sangat bagus. Bisakah Anda menerima jawaban sehingga orang lain tidak datang ke sini untuk menawarkan solusi ketika Anda sudah menemukannya? Terima kasih
Dasar
Jalur duplikat tidak benar-benar masalah. Sangat tidak mungkin bahwa Anda harus menambahkan direktori yang cukup PATHuntuk benar-benar menyebabkan masalah kinerja (terutama karena shell berhasil mencari cache).
chepner
5

Saya menggunakan fungsi di bawah ini di ~/.bashrc. Itu adalah sesuatu yang saya dapatkan dari sysadmin di lab lama saya, tetapi saya rasa dia tidak menulisnya. Cukup tambahkan baris ini ke Anda ~/.profileatau ~/.bashrc:

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

Ini memiliki berbagai keunggulan:

  • Menambahkan direktori baru ke $PATHsepele: pathmunge /foo/bar;
  • Ini menghindari entri yang digandakan;
  • Anda dapat memilih apakah akan menambahkan entri baru ke awal ( pathmunge /foo/baratau akhir ( pathmunge /foo/barsetelah) dari $PATH.

File inisialisasi shell Anda kemudian akan berisi sesuatu seperti:

pathmunge /some/dir
pathmunge /another/dir
pathmunge '/another/dir with spaces in it'
pathmunge /yet/another
pathmunge /and/another
pathmunge /end
terdon
sumber
Terima kasih. Tapi saya akan memilih solusi @ Starfish karena tidak muncul grep.
Niccolo M.
2
@NiccoloM. tidak masalah, terimalah yang Anda inginkan. Hati-hati dengan pendekatan bintang laut, itu akan mengeksekusi kode arbitrer melalui evalsehingga Anda dapat menyebabkan beberapa kerusakan serius jika Anda menjalankannya dengan argumen yang salah.
terdon
Perhatikan bahwa fungsi yang lebih cepat ada di redhat untuk melakukannya tanpa perintah eksternal grep, lihat bugzilla.redhat.com/show_bug.cgi?id=544652#c7
林果 林果
4

Saya ingin menambahkan, di ~ / .bashrc, beberapa direktori ke $ PATH saya.

Saya menggunakan yang berikut ini di Cygwin. Ini harus bekerja di versi lain dari bash. Anda dapat menghapus unset PATHuntuk membangun berdasarkan arus Anda PATH(jika Anda melakukan ini, Anda mungkin harus mencari cara menambahkan :pemisah dengan benar).

catatan:

  • Saya pernah memiliki fungsi ini dalam suatu bashfungsi tetapi hilang setelah crash disk.

Di saya .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}"

Di ~/.path_elements:

/home/DavidPostill/bin:
/usr/local/bin:
/usr/bin:
/c/Windows/system32:
/c/Windows
DavidPostill
sumber
Terima kasih. Jawaban Anda mengilhami saya untuk mengerjakan solusi serupa. (Menurut selera saya, menyimpan path dalam file terpisah adalah masalah.)
Niccolo M.
1

Saya menggunakan ini di .bashrc saya (dan juga .zshrc saya, karena saya biasanya menggunakan zsh di mana tersedia, bukan bash). Memang, ini mengharuskan saya untuk menambahkan direktori secara manual, tetapi keuntungannya adalah ketika saya memperbaruinya, saya dapat terus menyalinnya ke server baru dan tidak khawatir tentang PATH pada server baru yang dibuat dengan direktori yang tidak ada di sana.

##
## PATH
##
## Alih-alih hanya menghancurkan PATH kita dengan direktori yang mungkin
## tidak sesuai untuk server ini, cobalah untuk menjadi cerdas tentang apa yang kami tambahkan
##
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

Saya melakukan hal yang sama untuk MANPATH saya:

##
## MANPATH
##
## Alih-alih hanya mengalahkan MANPATH kami dengan direktori yang mungkin
## tidak sesuai untuk server ini, cobalah untuk menjadi cerdas tentang apa yang kami tambahkan
##
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

Selain memiliki satu file yang dapat saya salin ke sistem di lingkungan yang berbeda tanpa takut menambahkan direktori yang tidak ada ke PATH, pendekatan ini juga memiliki keuntungan memungkinkan saya untuk menentukan urutan saya ingin direktori muncul di PATH. Karena baris pertama dari setiap definisi sepenuhnya mendefinisikan ulang variabel PATH, saya dapat memperbarui. $ PATH = $ PATH: / new / dir ". Ini memastikan saya mendapatkan salinan bersih sesuai urutan yang saya inginkan.

Brian Snook
sumber
1
menyarankan alternatif: d="/usr/share/man" ; [ -d "$d" ] && MANPATH="$MANPATH:${d}"Ini akan lebih pendek, dan lebih mudah untuk menambahkan dir baru (cukup salin satu baris dan edit bagian "d = ...." pertama). Namun, untuk PATH satu, saya pikir Anda akan berakhir dengan terlalu banyak dir di PATH Anda, yang tidak selalu baik (bagaimana jika beberapa "foo" perintah ada di salah satu jalur yang kurang dikenal, dan melakukan sesuatu yang sama sekali berbeda bahwa apa yang diharapkan pengguna biasa?)
Olivier Dulac
OP meminta cara yang lebih singkat untuk menambahkan jalur. Ini jauh lebih bertele-tele dan lebih rentan kesalahan daripada apa yang sudah mereka coba hindari.
underscore_d
-1

Ada cara mudah! Baca Fungsi Shell dan Variabel Path di Linux Journal , 01 Mar 2000 Oleh Stephen Collyer

Fungsi ini memungkinkan saya menggunakan tipe data baru di lingkungan bash saya - daftar yang dipisahkan oleh titik dua. Selain PATH, saya menggunakannya untuk menyesuaikan LOCATE_PATH, MANPATH, dan lainnya, dan sebagai tipe data umum dalam pemrograman bash. Inilah cara saya mengatur PATH saya (menggunakan fungsi):

# 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

Karena tautan Linux Journal disebut sebagai "broken", saya telah meletakkan Fungsi Bash Path dalam file .shar di http://pastebin.ubuntu.com/13299528/

waltinator
sumber
3
Apa fungsinya? Bagaimana OP menggunakannya? Agaknya mereka dijelaskan dalam tautan yang terputus dalam jawaban Anda dan itulah sebabnya kami selalu ingin jawaban itu lengkap. Harap edit dan sertakan fungsi aktual dalam jawaban Anda.
terdon
@terdon: link berfungsi untuk saya, saya menaruh file .shar di pastebin, saya tidak akan memposting baris 1K di sini.
waltinator
Ups, bekerja untuk saya juga sekarang. Tidak ketika saya meninggalkan komentar. Pokoknya, inti dari komentar saya adalah bahwa kami mencoba menghindari tautan ke sumber daya eksternal sebagai jawaban. Kami ingin informasi berada di sini tempat informasi itu dapat diperbarui, diedit, dan kebal terhadap tautan busuk.
terdon