Dapatkan jalur skrip saat ini ketika dijalankan melalui symlink

59

Saya memiliki utilitas yang terdiri dari beberapa direktori dengan beberapa skrip bash dan file pendukung yang akan digunakan untuk beberapa mesin di direktori yang berbeda di setiap mesin. Script harus dapat mereferensikan path relatif ke diri mereka sendiri jadi saya harus bisa mendapatkan path ke file yang saat ini sedang dieksekusi.

Saya menyadari dirname $0idiom yang bekerja dengan sempurna ketika skrip saya dipanggil langsung. Sayangnya ada keinginan untuk dapat membuat symlink ke skrip ini dari direktori yang sama sekali berbeda dan masih memiliki pekerjaan logika pathing relatif.

Contoh dari keseluruhan struktur driectory adalah sebagai berikut:

/
 |-usr/local/lib
 |  |-foo
 |  |  |-bin
 |  |  |  |-script.sh
 |  |  |-res
 |  |  |  |-resource_file.txt
 |-home/mike/bin
 |  |-link_to_script (symlink to /usr/local/lib/foo/bin/script.sh)

Bagaimana saya dapat diandalkan referensi /usr/local/lib/foo/res/resource_file.txtdari script.shapakah itu dipanggil oleh /usr/local/lib/foo/bin/script.shatau ~mike/bin/link_to_script?

Mike Deck
sumber

Jawaban:

80

Coba ini sebagai solusi tujuan umum:

DIR="$(cd "$(dirname "$0")" && pwd)"

Dalam kasus spesifik symlink berikut, Anda juga bisa melakukan ini:

DIR="$(dirname "$(readlink -f "$0")")"
Caleb
sumber
Bekerja dengan sempurna dan jauh lebih sederhana daripada yang saya coba. Terima kasih!
Mike Deck
@MikeDeck Nikmati. Perhatikan bahwa saya memperbaiki beberapa masalah mengutip sejak posting pertama ... Anda mungkin menggunakan opsi dari edit terakhir jika Anda memiliki spasi atau karakter aneh lainnya di jalur Anda kapan-kapan. Bahkan jika itu tidak masalah untuk proyek ini, Anda dapat menyalin kode dari skrip Anda sendiri di jalan dan memiliki opsi terbaik yang penting!
Caleb
1
Saya harus mengklarifikasi, yang kedua bekerja dengan sempurna. Solusi pertama yang Anda berikan tidak berfungsi untuk symlink di sistem saya.
Mike Deck
4
@MikeDeck: Solusi pertama berfungsi untuk kasus tipikal memiliki berbagai direktori yang disinkronkan sebagai bagian dari path, tetapi tidak akan membantu jika biner terakhir adalah symlink. Itulah yang dikelola orang kedua.
Caleb
1
Tidak berfungsi jika file skrip adalah sourced (mis. $ source ./sript.sh) Ini berfungsi untuk kedua kasus:DIR="$(cd "$(dirname "$BASH_SOURCE")" && pwd)"
FractalSpace
7

satu baris:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))
diyism
sumber
2
Satu baris jawaban biasanya bukan yang paling bermanfaat. Silakan pertimbangkan memperluas jawaban Anda untuk memasukkan penjelasan, tautan, atau dokumentasi yang selanjutnya mendukung solusi yang Anda sarankan.
HalosGhost
1
sebenarnya, Anda tidak perlu melakukan ini, versi readlink dari jawaban asli berfungsi dengan baik jika tidak ada symlink yang terlibat sama sekali
PENULIS
3

readlink -f tidak bekerja untuk saya, saya memiliki kesalahan ini:

readlink: illegal option -- f
usage: readlink [-n] [file ...]

Tapi ini bekerja dengan baik:

DIR="$(dirname "$(readlink "$0")")"
echo $DIR
Kevin Campion
sumber
3
Maka Anda berada di Mac dan ini harus menjawab pertanyaan Anda .
Isaac
Ya, saya menggunakan MacOs @isaac, tapi saya tidak punya pertanyaan. Saya memposting perintah yang bekerja di sisi saya.
Kevin Campion
0

Satu tambahan kecil untuk skrip di atas. Opsi -P untuk pwd mengikuti symlink

DIR="$(cd "$(dirname "$0")" && pwd -P)"
pengguna2108420
sumber
7
Ini hanya berfungsi ketika symlink adalah bagian dari struktur direktori. Tidak berfungsi saat file itu sendiri ditautkan.
Oliver Gondža