Adakah yang menulis fungsi bash untuk menambahkan direktori ke $ PATH hanya jika belum ada di sana?
Saya biasanya menambahkan ke PATH menggunakan sesuatu seperti:
export PATH=/usr/local/mysql/bin:$PATH
Jika saya membuat PATH saya di .bash_profile, maka itu tidak dibaca kecuali sesi yang saya masuki adalah sesi login - yang tidak selalu benar. Jika saya membangun PATH saya di .bashrc, maka itu berjalan dengan setiap subkulit. Jadi jika saya meluncurkan jendela Terminal dan kemudian menjalankan layar dan kemudian menjalankan skrip shell, saya mendapatkan:
$ echo $PATH
/usr/local/mysql/bin:/usr/local/mysql/bin:/usr/local/mysql/bin:....
Saya akan mencoba membangun fungsi bash yang disebut add_to_path()
yang hanya menambahkan direktori jika tidak ada. Tetapi, jika ada yang sudah menulis (atau menemukan) hal seperti itu, saya tidak akan menghabiskan waktu untuk itu.
Jawaban:
Dari .bashrc saya:
Perhatikan bahwa PATH harus sudah ditandai sebagai diekspor, jadi tidak perlu mengekspor ulang. Ini memeriksa apakah direktori tersebut ada & adalah direktori sebelum menambahkannya, yang mungkin tidak Anda pedulikan.
Juga, ini menambahkan direktori baru ke ujung jalan; untuk meletakkannya di awal, gunakan
PATH="$1${PATH:+":$PATH"}"
alih-alihPATH=
baris di atas .sumber
":$PATH:"
bukan hanya"$PATH"
${PATH:+"$PATH:"}
${variable:+value}
berarti memeriksa apakahvariable
didefinisikan dan memiliki nilai yang tidak kosong, dan apakah itu memberikan hasil evaluasivalue
. Pada dasarnya, jika PATH bukan kosong untuk memulai dengan itu set ke"$PATH:$1"
; jika itu kosong itu hanya menetapkan"$1"
(perhatikan kurangnya titik dua).Memperluas jawaban Gordon Davisson, ini mendukung banyak argumen
Jadi Anda bisa melakukan pathappend path1 path2 path3 ...
Untuk mengawali,
Mirip dengan pathappend, Anda bisa melakukannya
pathprepend path1 path2 path3 ...
sumber
pathprepend P1 P2 P3
dan berakhir denganPATH=P1:P2:P3
. Untuk mendapatkan perilaku ini, ubahfor ARG in "$@" do
kefor ((i=$#; i>0; i--)); do ARG=${!i}
Inilah sesuatu dari jawaban saya untuk pertanyaan ini dikombinasikan dengan struktur fungsi Doug Harris. Ini menggunakan ekspresi reguler Bash:
sumber
$1
bukan${1}
Letakkan ini di komentar untuk jawaban yang dipilih, tetapi komentar tampaknya tidak mendukung pemformatan PRE, jadi tambahkan jawabannya di sini:
@ gordon-davisson Saya bukan penggemar besar kutipan & penggabungan yang tidak perlu. Dengan asumsi Anda menggunakan versi bash> = 3, Anda bisa menggunakan bash's built in regexs dan lakukan:
Ini tidak benar menangani kasus-kasus di mana ada ruang dalam direktori atau PATH. Ada beberapa pertanyaan apakah bash's yang dibangun di mesin regex cukup lambat sehingga net ini mungkin kurang efisien daripada penggabungan string dan interpolasi yang versi Anda lakukan, tapi entah bagaimana itu terasa lebih estetis bersih untuk saya.
sumber
formatting using the backtick
hanya mendukung tetapi Anda tidak mendapatkan kontrol paragraf yang layak.unnecessary quoting
menyiratkan Anda tahu sebelumnya bahwa$PATH
itu bukan nol."$PATH"
membuatnya OK apakah PATH adalah nol atau tidak. Demikian pula jika$1
berisi karakter yang mungkin membingungkan parser perintah. Menempatkan regex dalam tanda kutip"(^|:)$1(:|$)"
mencegah hal itu.[[
dan]]
. Saya lebih memilih untuk mengutip segala sesuatu yang mungkin dapat perlu dikutip, kecuali yang menyebabkannya gagal, tapi saya yakin dia benar, dan bahwa mengutip benar-benar tidak diperlukan sekitar$PATH
. Di sisi lain, menurut saya Anda benar tentang itu$1
.Ketika Anda membutuhkan $ HOME / nampan untuk muncul tepat sekali di awal $ PATH Anda dan tempat lain, tidak menerima pengganti.
sumber
PATH=${PATH/"
... daripadaPATH=${PATH//"
... untuk membuatnya bekerja.$1
satu-satunya entri (tanpa titik dua). Entri menjadi dua kali lipat.Berikut adalah solusi alternatif yang memiliki keuntungan tambahan untuk menghapus entru yang berlebihan:
Argumen tunggal untuk fungsi ini didahului dengan PATH, dan instance pertama dari string yang sama dihapus dari jalur yang ada. Dengan kata lain, jika direktori sudah ada di jalur, itu dipromosikan ke depan daripada ditambahkan sebagai duplikat.
Fungsi ini bekerja dengan menambahkan sebuah titik dua ke jalur untuk memastikan bahwa semua entri memiliki titik dua di bagian depan, dan kemudian menambahkan bagian baru ke jalur yang ada dengan entri yang dihapus. Bagian terakhir dilakukan menggunakan
${var//pattern/sub}
notasi bash ; lihat manual bash untuk lebih jelasnya.sumber
/home/robert
AndaPATH
dan Andapathadd /home/rob
.Ini milik saya (saya percaya itu ditulis bertahun-tahun yang lalu oleh Oscar, sysadmin dari lab lama saya, semua penghargaan kepadanya), sudah ada di bashrc saya selama berabad-abad. Ini memiliki manfaat tambahan yang memungkinkan Anda untuk menambahkan atau menambahkan direktori baru seperti yang diinginkan:
Pemakaian:
sumber
Untuk prepending, saya suka solusi @ Russell, tetapi ada bug kecil: jika Anda mencoba untuk menambahkan sesuatu seperti "/ bin" ke path "/ sbin: / usr / bin: / var / usr / bin: / usr / local / bin: / usr / sbin "itu menggantikan" / bin: "3 kali (ketika itu tidak benar-benar cocok sama sekali). Menggabungkan perbaikan untuk itu dengan solusi tambahan dari @ gordon-davisson, saya mendapatkan ini:
sumber
Alias sederhana seperti ini di bawah ini harus melakukan trik:
Yang dilakukannya hanyalah membagi jalur pada karakter: dan membandingkan setiap komponen dengan argumen yang Anda berikan. Grep memeriksa kecocokan garis lengkap, dan mencetak hitungan.
Penggunaan sampel:
Ganti perintah echo dengan addToPath atau alias / fungsi serupa.
sumber
Lihat Bagaimana mencegah duplikasi variabel jalur di csh? pada StackOverflow untuk satu set jawaban untuk pertanyaan ini.
sumber
Inilah yang saya siapkan:
Sekarang di .bashrc saya punya:
Versi terbaru mengikuti komentar tentang bagaimana dokumen asli saya tidak akan menangani direktori dengan spasi (berkat pertanyaan ini karena telah menunjukkan kepada saya untuk menggunakan
IFS
):sumber
PATH
mengandung spasi,*
,?
, atau[
...]
.Documents and Settings
danProgram Files
), tetapi Unix telah mendukung nama path yang mengandung spasi sejak sebelum Windoze ada.Saya agak terkejut bahwa belum ada yang menyebutkan ini, tetapi Anda dapat menggunakan
readlink -f
untuk mengubah jalur relatif ke jalur absolut, dan menambahkannya ke PATH.Misalnya, untuk meningkatkan jawaban Guillaume Perrault-Archambault,
menjadi
1. Dasar-Dasar - Apa Manfaat Hal Ini?
The
readlink -f
perintah akan (antara lain) mengkonversi path relatif ke path absolut. Ini memungkinkan Anda melakukan sesuatu seperti2. Mengapa Kami Menguji Berada di PATH Dua Kali?
Nah, perhatikan contoh di atas. Jika pengguna mengatakan dari direktori untuk kedua kalinya, akan . Tentu saja, tidak akan hadir di . Tapi kemudian akan ditetapkan ke (setara dengan path absolut dari ), yang merupakan sudah . Jadi kita perlu menghindari menambahkan untuk yang kedua kalinya.
pathappend .
/path/to/my/bin/dir
ARG
.
.
PATH
ARGA
/path/to/my/bin/dir
.
PATH
/path/to/my/bin/dir
PATH
Mungkin yang lebih penting, tujuan utama
readlink
adalah, seperti namanya, untuk melihat tautan simbolis dan membaca pathname yang dikandungnya (yaitu, menunjuk ke). Sebagai contoh:Sekarang, jika Anda berkata
pathappend /usr/lib/perl/5.14
, dan Anda sudah memiliki/usr/lib/perl/5.14
di PATH Anda, baik, itu baik-baik saja; kita bisa membiarkannya apa adanya. Tapi, jika/usr/lib/perl/5.14
tidak sudah di PATH Anda, kita sebutreadlink
danARGA
=/usr/lib/perl/5.14.2
, dan kemudian kita menambahkan bahwa untukPATH
. Tapi tunggu sebentar - jika Anda sudah mengatakanpathappend /usr/lib/perl/5.14
, maka Anda sudah memiliki/usr/lib/perl/5.14.2
dalam PATH Anda, dan, sekali lagi, kita perlu memeriksa itu untuk menghindari menambahkannya kePATH
yang kedua kalinya.3. Apa Kesepakatannya
if ARGA=$(readlink -f "$ARG")
?Jika tidak jelas, baris ini menguji apakah
readlink
berhasil. Ini hanya praktik pemrograman defensif yang bagus. Jika kita akan menggunakan output dari perintah m sebagai bagian dari perintah n (di mana m < n ), lebih baik untuk memeriksa apakah perintah m gagal dan menanganinya dengan cara tertentu. Saya tidak berpikir kemungkinan itureadlink
akan gagal - tetapi, seperti yang dibahas dalam Cara mengambil jalur absolut file sewenang-wenang dari OS X dan di tempat lain,readlink
adalah penemuan GNU. Ini tidak ditentukan dalam POSIX, jadi ketersediaannya di Mac OS, Solaris, dan Unix non-Linux lainnya dipertanyakan. (Bahkan, saya baru saja membaca komentar yang mengatakan "readlink -f
tampaknya tidak berfungsi di Mac OS X 10.11.6, tetapirealpath
bekerja di luar kotak. ”Jadi, jika Anda menggunakan sistem yang tidak memilikireadlink
, atau di manareadlink -f
tidak berfungsi, Anda mungkin dapat memodifikasi ini skrip untuk digunakanrealpath
.) Dengan memasang jaring pengaman, kami membuat kode kami agak lebih portabel.Tentu saja, jika Anda menggunakan sistem yang tidak memiliki
readlink
(ataurealpath
), Anda tidak akan mau melakukannya .pathappend .
-d
Tes kedua ([ -d "$ARGA" ]
) mungkin benar-benar tidak perlu. Saya tidak bisa memikirkan skenario di mana$ARG
direktori danreadlink
berhasil, tetapi$ARGA
bukan direktori. Saya hanya menyalin dan menempelkanif
pernyataan pertama untuk membuat yang ketiga, dan saya meninggalkan-d
tes karena malas.4. Ada Komentar Lain?
Ya. Seperti banyak jawaban lain di sini, yang ini menguji apakah setiap argumen adalah direktori, memprosesnya jika ada, dan mengabaikannya jika tidak. Ini mungkin (atau mungkin tidak) memadai jika Anda
pathappend
hanya menggunakan.
file " " (seperti.bash_profile
dan.bashrc
) dan skrip lainnya. Tetapi, seperti yang ditunjukkan oleh jawaban ini (di atas), sangat layak untuk menggunakannya secara interaktif. Anda akan sangat bingung jika melakukannyaSeperti yang saya katakan di atas, praktik yang baik untuk menangani kesalahan. Ini sebuah contoh:
sumber
readlink -f "$ARG"
. (2) Saya tidak tahu mengapa itu terjadi (terutama setelah-d "$ARG"
tes berhasil), tetapi Anda mungkin ingin menguji apakahreadlink
gagal. (3) Anda tampaknya mengabaikanreadlink
fungsi utama - untuk memetakan nama tautan simbolis ke "nama file asli". Jika (misalnya)/bin
adalah tautan simbolis ke/bin64
, maka panggilan berulangpathappend /bin
dapat menghasilkan perkataan PATH…:/bin64:/bin64:/bin64:/bin64:…
. Anda mungkin harus (juga) memeriksa apakah nilai baru$ARG
sudah masukPATH
..
pada contoh saya, saya percaya dapat dianggap sebagai nama file kanonik. Benar?readlink
namanya jelas menyiratkan tujuannya - ia melihat tautan simbolik dan membacakan pathname yang dikandungnya (yaitu, menunjuk ke). (2) Ya, saya katakan bahwa saya tidak tahu mengapareadlink
gagal. Saya membuat poin umum bahwa jika skrip atau fungsi berisi banyak perintah, dan perintah n dijamin gagal serempak (atau tidak masuk akal sama sekali) jika perintah m gagal (di mana m < n ), merupakan praktik yang baik dan bijaksana untuk memeriksa apakah perintah m gagal dan menangani dalam beberapa cara - setidaknya, ... (Lanjutan)readlink
bisa gagal jika (a) direktori diubah namanya atau dihapus (oleh proses lain) antara panggilan Anda ketest
danreadlink
, atau (b) jika/usr/bin/readlink
dihapus (atau rusak). (3) Anda sepertinya tidak mengerti maksud saya. Saya tidak mendorong Anda untuk menggandakan jawaban lain; Saya mengatakan bahwa, dengan memeriksa apakah dokumen asliARG
(dari baris perintah) sudah masukPATH
, tetapi tidak mengulangi pemeriksaan untuk yang baruARG
(keluaran darireadlink
), jawaban Anda tidak lengkap dan karena itu salah. … (Lanjutan)sumber
Cara ini berfungsi dengan baik:
sumber
Versi saya kurang hati-hati tentang jalur kosong dan bersikeras jalur yang valid dan direktori dari beberapa diposting di sini, tapi saya menemukan koleksi ish-ish dari prepend / append / clean / unique-ify / etc. fungsi shell berguna untuk manipulasi jalur. Seluruh lot, dalam keadaan saat ini, ada di sini: http://pastebin.com/xS9sgQsX (umpan balik dan perbaikan sangat disambut!)
sumber
Anda dapat menggunakan perl satu liner:
Ini dia di bash:
sumber
Saya sedikit mengubah jawaban Gordon Davisson untuk menggunakan dir saat ini jika tidak ada yang diberikan. Jadi Anda bisa melakukannya
padd
dari direktori yang ingin Anda tambahkan ke PATH Anda.sumber
Anda dapat memeriksa apakah variabel khusus telah disetel, jika tidak, atur kemudian tambahkan entri baru:
Tentu saja, entri ini masih dapat digandakan jika ditambahkan oleh skrip lain, seperti
/etc/profile
.sumber
Script ini memungkinkan Anda untuk menambahkan di akhir
$PATH
:Atau tambahkan di awal
$PATH
:sumber
Berikut adalah cara yang sesuai dengan POSIX.
Hal ini cribbed dari Guillaume Perrault-Archambault 'jawaban s pertanyaan ini dan mike511 ' s jawaban di sini .
UPDATE 2017-11-23: Fixed bug per @Scott
sumber
/etc/profile
. Direktori yang Anda coba tambahkan ke PATH mungkin sudah ada lebih dari sekali , dan kode Anda tersendat karenanya. … (Lanjutan)/a/ck
ke/b:/a/ck:/tr:/a/ck
, Anda mendapatkan/a/ck:/b:/a/ck:/tr:/tr:/a/ck
.