Temukan jalur absolut dari skrip

10

Dalam skrip saya mendapatkan $0jalur relatif yang memungkinkan untuk itu. Untuk mengubahnya menjadi absolut, saya telah menemukan solusi ini yang tidak saya mengerti:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

Masalah saya adalah keajaiban di dalam ${0%/*}dan ${0##*/}. Sepertinya mantan mengekstrak dirname dan yang terakhir mengekstrak nama file, saya hanya tidak mengerti caranya.

maaartinus
sumber
2
Itu menggunakan ekspansi parameter, tetapi tidak berhasil bagi saya. Jika skrip Anda hanya akan digunakan di Linux, Anda dapat menggunakan readlink -f $0untuk mendapatkan jalur kanonik.
Shawn J. Goff
1
@Shawn: 1 suara komentar yang bagus karena Anda memperkenalkan pemikiran yang tepat: "Itu menggunakan ekspansi parameter, tetapi tidak berhasil untuk saya". The dirnameutil berguna di sini.
D4RIO
mywiki.wooledge.org/BashFAQ/028 dan cyberciti.biz/faq/… mengatakan BASH_SOURCElebih baik daripada $0, seperti $0memberikan perintah yang diketik pengguna, yang mungkin bukan skrip yang sedang dieksekusi.
Joel Purra

Jawaban:

8

Definisi:

${string%substring} menghapus kecocokan terpendek $substringdari akhir $string.

${string##substring}menghapus kecocokan terlama $substringsejak awal $string.

Contoh Anda:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

${0%/*} menghapus semuanya setelah slash terakhir, memberi Anda nama direktori skrip (yang mungkin merupakan jalur relatif).

${0##*/} menghapus semuanya hingga tebasan terakhir, memberi Anda hanya nama skrip.

Jadi, perintah ini berubah ke direktori skrip dan menggabungkan direktori kerja saat ini (diberikan oleh $PWD) dan nama skrip yang memberi Anda jalur absolut.

Untuk melihat apa yang sedang terjadi coba:

echo ${0%/*}
echo ${0##*/}
dogbane
sumber
Tambahkan tanda kutip ganda di sekitar semua ekspansi variabel untuk mengatasi (hampir semua) nama file yang berisi karakter khusus shell.
Gilles 'SO- stop being evil'
10

Shawn memiliki solusi yang paling sederhana: readlink -f $0. Jika Anda ingin benar-benar yakin menangani nama file yang aneh, Anda dapat menggunakan ini:

absolute_path_x="$(readlink -fn -- "$0"; echo x)"
absolute_path="${absolute_path_x%x}"

Dokumentasi

l0b0
sumber
1
Bagus untuk melihat baris terakhir ditangani dengan benar. Sayangnya readlink -fnkhusus untuk Linux, NetBSD dan OpenBSD.
Gilles 'SANGAT berhenti menjadi jahat'
4

Berikut ini cara yang lebih aman dan lebih mudah dibaca untuk melakukan pekerjaan ini:

abspath=$(unset CDPATH && cd "$(dirname "$0")" && echo $PWD/$(basename "$0"))

Catatan:

  • Jika $0nama file telanjang tanpa jalur sebelumnya, skrip asli akan gagal tetapi yang diberikan di sini akan berfungsi. (Tidak masalah dengan $0tetapi bisa di aplikasi lain.)
  • Salah satu pendekatan akan gagal jika jalur ke file tidak benar-benar ada. (Tidak masalah dengan $0, tetapi bisa di aplikasi lain.)
  • Sangat unsetpenting jika pengguna Anda mungkin telah CDPATHmengatur.
  • Tidak seperti readlink -fatau realpath, ini akan bekerja pada Unix versi non-Linux (misalnya, Mac OS X).
Matthias Fripp
sumber
2

Jika Anda ingin mempelajari Shell Parameter Expansion, Anda dapat membacanya dari sini , tetapi Ekspansi tidak selalu merupakan pilihan yang baik. Dalam hal ini, hampir setiap sistem seperti Unix memiliki 2 utilitas yang baik:

basename
dirname

Yang pertama akan mengekstrak nama file, sedangkan yang kedua akan mengekstrak path, jadi, jika Anda memiliki $ 0, katakan:

dirname $0

Dan Anda akan mendapatkan jalannya.

Bersulang

D4RIO
sumber
dirname dapat mengembalikan jalur relatif
opticyclic
0

Memperkenalkan pwd, bash builtin. Juga ditemukan dalam paket GNU coreutils.

$ sh ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
$0: ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
cheeky binary from /home/jaroslav/tmp (/home/jaroslav/tmp)

$ cat /home/jaroslav/tmp/somewhere.sh

abs=$( cd `dirname "$0"` ; pwd -P)
absBin=$( cd `dirname "$0"` ; /bin/pwd -P)
echo \$0: $0
echo cheeky binary from $abs \($absBin\)
Ярослав Рахматуллин
sumber