exec-path dan $ PATH

28

Saya telah melihat contoh online di mana orang menambahkan jalur ke jalur default di Emacs dengan:

(add-to-list 'exec-path "/usr/local/bin/")

Saya baru mengenal Elisp, dan saya pikir saya mengerti apa yang dilakukan pernyataan di atas, tetapi saya punya beberapa pertanyaan:

  • Dalam urutan apa Emacs mencari melalui jalur eksekusi? Misalnya, apakah ia menganggap nilai $PATH(variabel env) sama sekali (dan jika ya, sebelum atau sesudah exec-path?)

  • Bagaimana saya bisa menambahkan beberapa jalur seperti itu? Bisakah saya terus menyatukan mereka? misalnya

    (add-to-list 'exec-path "PATH1", "PATH2")
    

    atau yang harus saya lakukan:

    (add-to-list 'exec-path "PATH1:PATH2:PATH3") 
    

Saya juga menemukan paket menarik ini di GitHub: exec-path-from-shell . Mengapa ada kebutuhan untuk paket untuk ini?

Motivasi

Pernah menemukan bahwa perintah bekerja di shell Anda, tetapi tidak di Emacs?

Ini banyak terjadi pada OS X, di mana instance Emacs dimulai dari GUI mewarisi serangkaian variabel lingkungan default.

Pustaka ini berfungsi memecahkan masalah ini dengan menyalin variabel lingkungan penting dari shell pengguna: ia bekerja dengan meminta shell Anda untuk mencetak variabel yang diminati, lalu menyalinnya ke lingkungan Emacs.

Amelio Vazquez-Reina
sumber
3
Selamat Datang di Emacs dan Elisp! Saya sendiri masih cukup baru dengan topik itu dan tidak tahu jawaban atas pertanyaan Anda, tetapi saya pikir saya akan menyebutkan sesuatu yang telah membuat hidup menjadi jauh lebih mudah: fungsi yang diuraikan. misalnya (describe-function 'add-to-list)( C-h f) akan memberi Anda dokumen untuk add-to-listfungsi tersebut, serta tautan ke sumbernya. Ada juga (describe-variable 'exec-path)( C-h v). Ini tidak dimaksudkan untuk menjadi komentar RTFM - dokumen ini tidak menjawab semua pertanyaan yang Anda daftarkan, hanya sesuatu yang bermanfaat.
jtmoulia
Terima kasih @jtmoulia! Saya pasti akan mengingatnya untuk pertanyaan di masa depan.
Amelio Vazquez-Reina
Selain itu C-h v exec-path, gunakan manual (Emacs dan Elisp). Dalam manual, i exec-pathmengarahkan Anda ke penjelasan yang bermanfaat. Tanyakan Emacs dulu - Anda tidak akan menyesal melakukannya.
Drew

Jawaban:

23

1) PATHdanexec-path

Emacs tidak ditentukan exec-pathdari nilai PATHsaat startup, tetapi tidak akan melihatnya lagi nanti. Tetapi jika Anda menjalankan perintah, itu akan mewarisi PATH, tidak exec-path, sehingga subproses dapat menemukan perintah yang berbeda dari yang Emacs lakukan.

Seperti dikatakan Francesco, ini bisa sangat membingungkan shell-command, karena itu tidak menjalankan proses secara langsung, tetapi memanggil shell untuk menjalankannya, yang akan digunakan PATH, bukan exec-path.

2) Menambahkan beberapa jalur ke exec-path

Panggil saja add-to-listberulang kali:

(add-to-list 'exec-path "PATH1")
(add-to-list 'exec-path "PATH2")

Perhatikan bahwa add-to-listmenambahkan ke awal daftar, jadi ini akan berakhir dengan "PATH2"berada di exec-pathsebelumnya "PATH1".

Anda juga dapat menggunakan lebih banyak akses "tingkat rendah" ke daftar:

(setq exec-path (append '("PATH1" "PATH2")
                        exec-path))

Ini akan menambah "PATH1"dan "PATH2"ke Anda exec-path, dalam urutan itu.

3) PATH Mac OS

Masalah pada Mac OS X adalah bahwa Mac OS tidak mengatur lingkungan yang sama ketika Anda memanggil program dari UI global atau ketika Anda menyebutnya dari shell. Ini berarti menjalankan Emacs dari shell akan menghasilkan variabel lingkungan yang berbeda yang ditetapkan daripada ketika Anda menjalankannya dari finder. Ini sangat menjengkelkan jika Anda mengatur variabel lingkungan .bashrcatau sejenisnya, karena itu tidak akan memengaruhi Emacs "global".

Paket tersebut tampaknya memulai sebuah shell dan mengimpor variabel lingkungan dari sana, meniru lingkungan yang Anda dapatkan dari sebuah shell di Emacs yang dimulai secara global.

Jorgen Schäfer
sumber
Terima kasih Jorgen. Mengenai Q3: Apakah Anda tahu di mana default PATHdidefinisikan untuk program yang dimulai dari UI global (lingkungan desktop)? Saya mengalami masalah yang sama dengan PYTHONPATHdi elpy:). Ketika saya memulai Emacs dari desktop, Emacs tidak mengetahui PYTHONPATHdefinisi saya dalam .zshenvfile saya (file init untuk zsh), yang sangat membuat frustrasi, karena elpytidak tahu lalu ke mana menemukan paket Python saya. Saya senang memindahkan PYTHONPATHdefinisi ini ke initfile shell yang berbeda (walaupun idealnya saya ingin Emacs menggunakan definisi dari saya .zshenv)
Amelio Vazquez-Reina
Saya takut saya tidak tahu sama sekali tentang Mac OS X. Google cepat membuat saya ke stackoverflow.com/questions/135688/... yang tampaknya menunjukkan bahwa launchd.conf adalah tempat yang tepat. Jika yang Anda butuhkan untuk ini adalah Emacs, Anda tentu saja dapat mengatur keduanya exec-pathdan PATHdi Anda .emacs. Anda dapat mengatur PATHmenggunakan (setenv "PATH" (format "%s:%s" "/new/path/element" (getenv "PATH"))).
Jorgen Schäfer
Terima kasih. Saya tahu Q berikut menyimpang sedikit dari OP, tetapi apakah ada cara untuk menentukan dalam Emacs PYTHONPATHyang elpyharus digunakan?
Amelio Vazquez-Reina
Anda dapat memodifikasi process-environment, misalnya menggunakan setenv. Anda dapat melakukannya elpy-mode-hook, tetapi ini adalah variabel globsl dan menjadikannya buffer-local dapat dengan mudah menyebabkan perilaku membingungkan.
Jorgen Schäfer
9

Ketika emacs memulai proses eksternal baru menggunakan fungsi primitif seperti call-processatau start-process, executable dicari exec-path(dan tidak $PATH)

Namun, fungsi seperti shell-commandmemulai shell sebagai subproses dan meneruskannya perintah yang ingin Anda jalankan. Untuk menjalankan perintah ini, shell kemudian akan mencoba untuk menemukan executable di $PATH(dan bukan di exec-path).

Oleh karena itu, exec-pathyang paling penting untuk proses eksternal yang dimulai oleh emacs itu sendiri, sedangkan $PATHapa yang diperhitungkan untuk perintah yang Anda jalankan sendiri dengan fungsi tingkat yang lebih tinggi (menggunakan M-!misalnya)


Jika Anda ingin menambahkan beberapa direktori exec-path, Anda harus menggunakan add-to-listbeberapa kali.

Anda dapat melakukannya secara manual

(add-to-list 'exec-path "dir1")
(add-to-list 'exec-path "dir2")

atau menggunakan loop

(dolist (dir '("dir1" "dir2"))
  (add-to-list 'exec-path dir))

Mengenai pertanyaan ketiga Anda, jika emacs diluncurkan dari lingkungan desktop, itu mewarisi lingkungan dari itu, yang mungkin kurang lengkap dibandingkan dengan shell penuh.

Ini berarti bahwa kadang-kadang mungkin perlu untuk melengkapi nilai Emacs untuk $PATHmenggunakan apa yang dilihat oleh shell biasa. Ini adalah tujuan exec-path-from-shellperpustakaan yang Anda sebutkan.

ffevotte
sumber