Bagaimana saya mendapatkan 'jalur jalan' untuk menemukan tautan simbolis saya?

13

Saya menggunakan MacOSX bashsebagai shell saya. Saya memiliki tautan simbolis, dibuat seperti ini:

ln -s /usr/bin/python python2 

Saya memiliki paket yang menggunakan python2 dan saya ingin membuat tautan simbol di direktori kerja saya saat ini /usr/bin/pythonyang sebenarnya adalah python2. Ketika saya melakukan python2dari baris perintah saya mendapatkan kesalahan ini:

python2: realpath couldn't resolve "/usr/bin/python2"

Tetapi menjalankannya seperti ini akan ./python2menyelesaikan jalur dengan benar. Saya PATHmemiliki .di dalamnya. Bahkan saya memodifikasinya, untuk pengujian, hanya ada .di dalamnya.

Bagaimana saya mengatasi ini? Terima kasih!


Konteks

Sejumlah solusi yang disarankan di bawah ini tidak akan berfungsi untuk saya. Saya mencoba menyaring pertanyaan saya dengan fokus dan sesingkat mungkin sehingga orang tidak akan tenggelam dalam lautan teks, tetapi jelas saya perlu memberikan lebih banyak latar belakang.

Saya mencoba mengembangkan paket yang saya kloning dari git. Paket asli git-multimail,, adalah / dikembangkan pada beberapa varian Linux (saya rasa Ubuntu). Saya sudah mencoba memodifikasinya untuk dapat menggunakannya dan test suite-nya di MacOSX dengan sesedikit mungkin modifikasi. Inilah mengapa beberapa solusi yang diusulkan tidak ideal:

  1. Sebagai root, buat python2symlink di / usr / bin /. Saya mencari solusi yang tidak memerlukan ini. Ini adalah pilihan yang jelas di awal, tetapi saya ingin solusi yang memodifikasi sistem host sesedikit mungkin. Inilah sebabnya saya ingin membuat symlink sementara di direktori kerja saat ini, menambahkan CWD (ie .) ke path saya, dan kemudian menghancurkan ini ketika selesai (yaitu symlink).

  2. Buat skrip wrapper untuk memanggil skrip python dengan python yang ada. Masalah dengan ini adalah bahwa banyak dari test suite menggunakan script_files yang sebenarnya sebagai executable, tergantung pada shebang untuk menemukan lingkungan eksekusi yang benar. Ini berarti mengedit test suite secara signifikan. Dalam konteks ini, (lihat di bawah untuk potongan kerangka uji), saya harus menambahkan pembungkus untuk setiap .pyfile; lebih lanjut pengguna / pengembang harus menyadari aturan yang berbeda untuk menggunakan paket tergantung pada sistem mereka (yaitu pada MacOSX pastikan Anda tidak menggunakan file python tanpa memohonnya melalui pembungkus atau secara eksplisit memanggil /usr/bin/python file.py).

    #! /bin/sh
    
    D=$(cd $(dirname "$0") && pwd)
    MULTIMAIL="$D/../git-multimail/git_multimail.py"
    POST_RECEIVE="$D/../git-multimail/post-receive"
    
    TESTREPO=$("$D/create-test-repo")
    
    HOME="$D"
    XDG_CONFIG_HOME="$D"
    GIT_CONFIG_NOSYSTEM=1
    export HOME XDG_CONFIG_HOME GIT_CONFIG_NOSYSTEM
    
    cd $TESTREPO
    
    test_email() {
        REFNAME="$1"
        OLDREV="$2"
        NEWREV="$3"
        echo "$OLDREV" "$NEWREV" "$REFNAME" | USER=pushuser "$MULTIMAIL"
    
    } 
  3. Mengubah semua python2referensi ke python. README menyarankan ini, tetapi ini secara efektif membuat kontrol versi tidak berguna karena sistem melihat perubahan sebagai versi baru, padahal sebenarnya tidak (semantik).

Saya telah menggunakan (3) tetapi saya mencoba mencari solusi yang lebih baik. Saya bersedia menerima bahwa ini memang keadaannya semula (yaitu tidak ada cara yang cocok untuk menunjukkan 'python2' ke /usr/bin/pythonyang portabel dan tidak mencolok tanpa banyak perubahan pada test suite dan kerangka kerja sebenarnya).

Avery Chan
sumber
1
Hei! Justln -s /usr/bin/python /usr/bin/python2
enedil
Memang saya mengembangkan git-multimail di Linux. Tapi saya akan menyambut patch dan penguji untuk membuatnya berfungsi pada OS X. BTW, masalah "python2" Anda terpecahkan sekarang, karena git-multimail menerima baik python2 dan python3 :-).
Matthieu Moy
Pertanyaan yang diperluas masih melewatkan detail penting: seperti apa garis shebang dalam skrip yang dapat dieksekusi? Untuk git-multimail.pyitu #!/usr/bin/env python2, jadi ada cara (relatif) langsung untuk melakukan ini.
alexis
Komentar @ enedil tidak berhasil, namun ln -s /usr/bin/python2.7 /usr/local/bin/python2berhasil
Phylliida

Jawaban:

3

Jika Anda perlu menyelesaikan (atau menyelidiki) symlink, Anda dapat menggunakan pustaka bash platform independen 'realpath-lib'. Secara default ini mengemulasi readlink dan akan berfungsi pada Mac atau Unix. Itu dapat ditemukan di Github atau Bitbucket dan gratis.

Tapi sepertinya Anda hanya ingin melakukan python2 (daripada ./python2) dari direktori (kerja) lokal Anda. Dimungkinkan untuk melakukan ini dengan alias di .bashrc Anda atau Anda harus menambahkan direktori kerja (yang berisi symlink Anda) ke variabel lingkungan PATH Anda. Ini juga dapat dilakukan untuk sesi saat ini saja atau dalam file .bashrc untuk sesi mendatang. Ini bisa menjadi solusi hanya untuk pengguna tertentu.

Opsi lain yang akan bekerja untuk semua pengguna adalah membuat symlink python2 ke / usr / bin / python di direktori lain di path, katakan di / usr / local / bin. Mungkin kira-kira seperti:

sudo ln -s /usr/bin/python /usr/local/bin/python2

Maka setiap pengguna atau skrip harus menemukan perintah python atau python2. Tentu saja opsi ini membutuhkan hak admin (root) untuk menginstal.

AsymLabs
sumber
Saya akhirnya menyerah. Ada terlalu banyak tempat yang menganggap 'python2' dalam kode dan tidak setiap solusi terlokalisasi mencakup semua kemungkinan. Ini adalah palu godam yang paling tepat untuk kuku ini.
Avery Chan
@Setiap, apakah Anda mencoba solusi saya? Apakah ada masalah? Itu tidak akan mengharuskan Anda untuk menambahkan python2ke /usr/bin(meskipun saya melihat yang menambahkannya sebagai perbaikan, jujur).
alexis
Dimungkinkan untuk melakukan ini dengan alias (...) Itu tidak mungkin karena alias hanya memengaruhi baris perintah dan bukan skrip. Lihat Bagaimana mengubah versi default Python di Debian 7.5?
Piotr Dobrogost
15

Saya percaya Anda sedang bertabrakan dengan sistem Apple untuk mengelola dan beralih di antara beberapa versi dari program yang sama. Anda dapat mencapai apa yang Anda inginkan, kurang elegan tetapi tanpa masalah, dengan skrip berikut bernama python2:

#!/bin/bash
exec /usr/bin/python "$@"

Jadikan itu dapat dieksekusi ( chmod +x python2), dan Anda berada dalam bisnis.

Penjelasan masalah:

Ketika Anda menjalankan /usr/bin/python, itu menemukan dan mengeksekusi python2.7 di direktori yang sama. Tautan simbolis Anda gagal karena sistem mengikuti symlink /usr/bin, lalu mencari dan gagal menemukan di python2 sana. Anda bisa selangkah lebih maju dengan menggunakan "tautan keras" alih-alih tautan simbolis:

rm python2
ln /usr/bin/python python2

Sekarang tidak ada tautan simbolis untuk diikuti, hanya dua nama file untuk file yang sama (inode). Tetapi sekarang saya gagal dengan pesan berikut:

python2: posix_spawn: /Users/alexis/.../python22.7: No such file or directory

Perhatikan python22.7: Kerangka kerja ini menambah 2.7nama yang Anda buat! Alih-alih mencoba mengungkap ini dan mengatur hutan tautan yang sesuai dengan harapannya, saya sarankan Anda menghindari kerangka kerja manajemen versi, dan gunakan solusi yang disarankan di atas.

PS. Mungkin ada solusi yang lebih baik: Jika Anda akan menjelaskan apa yang perlu Anda lakukan untuk memulainya (mengapa Anda perlu memberikan python2sebagai alias untuk python), seseorang mungkin dapat membantu Anda melakukannya dengan cara yang berbeda. Ini dikenal sebagai "masalah XY" dalam istilah stackexchange ...

Alexis
sumber
Ketika Anda menjalankan /usr/bin/python, ia menemukan dan mengeksekusi python2.7 di direktori yang sama. Pernyataan ini sangat membingungkan. Jika Anda menggambarkan kasus di mana /usr/bin/pythonsymlink maka harap lebih spesifik.
Piotr Dobrogost
itu sangat buruk ..
Nicolas
Apa yang luar biasa buruk?
alexis
2

Mencoba:

ln -s /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /usr/local/bin/python2
Liangmin Li
sumber
Tidak tahu mengapa Anda menerima downvotes, ini adalah satu-satunya solusi yang bekerja untuk saya
xApple
1

Anda dapat menggunakan perintah Unix readlinkuntuk mencari tahu jalur fisik tautan.

Contohnya

Katakanlah saya memiliki tautan berikut:

$ ls -l /usr/bin/etags
lrwxrwxrwx. 1 root root 29 Dec 10 22:56 /usr/bin/etags -> /etc/alternatives/emacs.etags

$ ls -l /etc/alternatives/emacs.etags
lrwxrwxrwx. 1 root root 20 Dec 10 22:56 /etc/alternatives/emacs.etags -> /usr/bin/etags.ctags

$ ls -l /usr/bin/etags.ctags
lrwxrwxrwx. 1 root root 5 Dec 10 22:56 /usr/bin/etags.ctags -> ctags

  1. Untuk menemukan nilai yang ditunjukkan tautan simbolik

    $ readlink /usr/bin/etags
    /etc/alternatives/emacs.etags

    CATATAN: Hasil di atas dapat berupa tautan lain. Untuk mengatasi ini lihat # 2 di bawah ini.

  2. Untuk mengetahui jalur absolut dari nilai yang ditunjukkan oleh tautan simbolik

    $ readlink -f /usr/bin/etags
    /usr/bin/ctags
slm
sumber
0

Saya tidak mengerti - bagaimana Anda percaya bahwa tautan pembungkus itu ok, tetapi bukan skrip pembungkus ? Salah satunya hanyalah tingkat tipuan. Dan bukankah Anda masih harus menginstruksikan pengguna Anda hanya untuk memanggilnya dari direktori tertentu?

Bagaimanapun, Anda bisa mendapatkan direktori kerja saat ini $PATHtentu saja:

 echo "echo \"Hi! I'm python\"" >|./python 
 chmod +x ./python 
 PATH="${PWD}:${PATH}" 
 python

 #OUTPUT#
 Hi! I'm python

 rm python 
 python -V 
 ln -s /usr/bin/python2 ./python 
 python -V

 #OUTPUT#
 Python 3.4.0
 Python 2.7.6

 PATH="${PATH#"${PWD}:"}" 
 python -V

 #OUTPUT#
 Python 3.4.0

Silahkan ambil . keluar dari Anda $PATH. Itu ide yang mengerikan.

mikeserv
sumber
Mengapa .di $ PATH saya ide yang buruk? Jika saya meletakkannya di akhir, maka tempat terakhir yang akan dilihat adalah direktori kerja saya saat ini (yaitu `PATH =" $ {PATH}: $ {PWD} ". Sebuah skrip wrapper berarti bahwa untuk setiap file python saya akan harus membuat file tambahan. Tautan pembungkus ke executable python hanya membuat satu hal yang harus saya lakukan
Avery Chan
@ AveryChan saya tidak berpikir begitu. Skrip wrapper dapat mengambil fungsi shell atau alias dengan nama yang sama dengan yang dapat dieksekusi. Bisa juga --bind mountdieksekusi di direktori saat ini atau (hanya linux, saya kira) bahkan chrootseperlunya. Tapi dalam $PATHkarya untuk direktori apa pun dan tidak spesifik. Ini berbahaya bagi pengguna Anda. Bagaimanapun, saya dengan sangat jelas menunjukkan bagaimana melakukannya di atas. Apakah itu tidak memenuhi persyaratan Anda?
mikeserv