Entri duplikat dalam $ PATH masalah?

45

Saya sumber bashrc dari beberapa teman saya. Jadi saya akhirnya memiliki entri duplikat dalam variabel $ PATH saya. Saya tidak yakin apakah itu masalah untuk perintah yang butuh waktu lama untuk memulai. Bagaimana cara kerja $ PATH di bash secara internal? Apakah memiliki lebih banyak PATHS memperlambat waktu mulai saya?

balki
sumber

Jawaban:

42

Memiliki lebih banyak entri $PATHtidak secara langsung memperlambat startup Anda, tetapi itu memperlambat setiap kali Anda pertama kali menjalankan perintah tertentu dalam sesi shell (tidak setiap kali Anda menjalankan perintah, karena bash menyimpan cache). Perlambatan jarang terlihat kecuali Anda memiliki sistem file yang sangat lambat (misalnya NFS, Samba atau sistem file jaringan lainnya, atau di Cygwin).

Entri duplikat juga sedikit mengganggu ketika Anda meninjau $PATHvisual Anda, Anda harus mengarungi lebih banyak cruft.

Cukup mudah untuk menghindari menambahkan entri rangkap.

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

Catatan: sumber skrip shell orang lain berarti mengeksekusi kode yang dia tulis. Dengan kata lain, Anda memberi teman Anda akses ke akun Anda kapan pun mereka mau.

Catatan: .bashrcbukan tempat yang tepat untuk mengatur $PATHatau variabel lingkungan lainnya. Variabel lingkungan harus ditetapkan ~/.profile. Lihat File pengaturan mana yang harus digunakan untuk mengatur variabel lingkungan dengan bash? , Perbedaan antara .bashrc dan .bash_profile .

Gilles 'SANGAT berhenti menjadi jahat'
sumber
8
+1: tidak dapat menekankan bahwa "cukup memberi teman Anda akses ke akun Anda". Bahkan jika tidak ada upaya untuk melukai Anda, skrip mereka mungkin saja yang mereka butuhkan dan masih makan siang saat Anda sumbernya.
msw
Salah satu masalah yang mungkin terjadi dengan solusi ini adalah jika $ new_entry sudah menjadi entri pertama di PATH, ": $ new_entry:" tidak akan cocok. Saya memperbaiki ini di profil saya dengan mengecualikan titik awal ':'.
Jeff Bauer
@ Jeff Jauer Saya tidak melihat masalah. Saya menggunakan case :$PATH:dan tidak case $PATHsehingga cocok meskipun entri pertama atau terakhir.
Gilles 'SANGAT berhenti menjadi jahat'
31

Saya telah melihat orang-orang membersihkan duplikat dari variabel PATH mereka menggunakan awkdan sesuatu seperti ini:

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

Anda bisa mencoba menambahkannya ke bashrc Anda sendiri dan pastikan Anda sumber file lain di suatu tempat sebelum menjalankannya.

Sebuah alternatif akan menggunakan yangpathmerge utilitas.

Adapun masalah kecepatan Anda, ini tidak akan mempengaruhi waktu startup shell dengan cara yang signifikan tetapi mungkin menghemat waktu melakukan penyelesaian tab untuk perintah, terutama ketika perintah tidak ditemukan di jalan dan itu pencarian berulang melalui yang sama folder mencarinya.

Catatan tentang keamanan: Anda harus benar - benar memperhatikan peringatan Gilles tentang keamanan di sini. Dengan sumber file yang dimiliki oleh pengguna lain Anda memberikan izin gratis kepada para pengguna untuk mengeksekusi kode mereka sendiri sebagai pengguna Anda setiap kali Anda memulai sebuah shell. Jika Anda tidak mempercayai pengguna tersebut dengan kata sandi Anda, Anda seharusnya tidak mencari file shell mereka.

Caleb
sumber
6
Saya suka awk one-liner, tetapi ia mencetak ORS trailing ':'. Jadi saya memodifikasinya menjadi bacaPATH=$(echo "$PATH" | awk -v RS=':' -v ORS=":" '!a[$1]++{if (NR > 1) printf ORS; printf $a[$1]}')
gkb0986
Trailing :tidak hanya masalah kosmetik. Ini sama dengan menambahkan .ke jalur Anda, yang berpotensi berbahaya.
wisbucky
Saya telah mengedit jawaban untuk menyertakan perbaikan dari gkb0986.
Tim Lesher
@TimLesher Alasan saya tidak pernah mengedit dari pada oleh jawaban adalah bahwa itu tidak bekerja untuk saya .... dan yang asli tanpanya bekerja (termasuk tidak meninggalkan pemisah jejak. Saya tidak tahu apa bedanya .
Caleb
1
@ gkb0986 Solusi ini masih gagal jika path berisi ruang yang diloloskan, seperti PATH = / bin: / foo \ bar: / usr / bin. Saya menemukan varian yang menghindari ini di unix.stackexchange.com/a/124517/106102
maharvey67
13

Berdasarkan jawaban @Gilles Anda dapat membungkusnya dalam fungsi untuk meminimalkan mengetik:

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
hwde
sumber
1
Jawaban yang paling bisa digunakan secara praktis (tingkat tinggi, mungkin).
ijoseph
3

Hanya pertandingan pertama $PATHyang dijalankan, sehingga setiap entri berikutnya tidak diproses setelah itu. Itu sebabnya Anda terkadang harus merevisi urutan entri di Anda $PATHuntuk membuat lingkungan Anda berperilaku seperti yang diharapkan.

Untuk menjawab pertanyaan Anda: ini seharusnya tidak menjadi penyebab startup lambat.

Rajish
sumber
1
Tapi itu membutuhkan waktu lebih lama ketika saya mengetik perintah yang tidak ada. Ini akan mencari folder yang sama dua kali untuk perintah.
balki
@ Balki Maksud Anda menyelesaikan perintah TAB? Dalam hal ini Anda harus memeriksa apakah Anda melengkapi definisi yang tidak terlihat complete -c which -a. Anda harus menghapus -aparameter. Anda dapat memeriksa bahwa dengan mengeluarkan perintah: complete | grep which.
Rajish
Ini masih bisa menjadi masalah jika mencari direktori yang sama yang tidak berkali-kali sebelum menemukannya.
Random832
-1

Untuk mencegah entri duplikat di PATH saya, saya harus meletakkan yang berikut di KEDUA ~ / .bash_profile dan ~ / .bashrc:

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

Kelemahan utama adalah bahwa entri entri PATH, tapi saya pikir saya bisa hidup dengan itu.

John Reynolds
sumber
Urutan pencarian PATH cukup penting.
Steven Shaw