Lihat file di bawah direktori yang sama dari skrip yang ditemukan di $ PATH

33

Saya memiliki file skrip bash, yang diletakkan di bawah beberapa direktori yang ditambahkan ke $ PATH sehingga saya dapat memanggil skrip dari direktori mana pun.

Ada file teks lain di bawah direktori yang sama dengan skrip. Saya ingin tahu bagaimana merujuk ke file teks dalam skrip?

Misalnya, jika skrip hanya untuk menampilkan konten file teks, cat textfiletidak akan berfungsi, karena ketika memanggil skrip dari direktori yang berbeda, file teks tidak ditemukan.

Tim
sumber
Masalah terkait baru-baru ini muncul di sini: Dapatkan lintasan skrip saat ini ketika dijalankan melalui symlink
Caleb
Pertanyaan ini menjawab bagaimana cara mendapatkan path file skrip bash dengan andal, saya menambahkannya ke path saya: stackoverflow.com/q/4774054/1695680
ThorSummoner

Jawaban:

24

Ini harus bekerja sama, selama tidak ada symlink (dalam perluasan jalur atau skrip itu sendiri):

  • MYDIR="$(dirname "$(realpath "$0")")"

  • MYDIR="$(dirname "$(which "$0")")"

  • Versi dua langkah dari yang di atas:

    MYSELF="$(realpath "$0")"

    MYDIR="${MYSELF%/*}"

Jika ada symlink dalam perjalanan ke skrip Anda, maka whichakan memberikan jawaban tidak termasuk resolusi tautan itu. Jika realpathtidak diinstal secara default pada sistem Anda , Anda dapat menemukannya di sini .

[EDIT]: Karena tampaknya realpathtidak memiliki kelebihan dibandingkan yang readlink -f disarankan oleh Caleb , mungkin lebih baik menggunakan yang terakhir. Tes waktu saya menunjukkan itu sebenarnya lebih cepat.

rozcietrzewiacz
sumber
Tidak masalah. Omong-omong dari mana realpathdatangnya dari sistem Anda. (Untuk orang lain yang tidak memilikinya, Anda dapat menggunakanreadlink -f
Caleb
@ Caleb Sebenarnya saya pikir itu milik seperangkat utilitas GNU standar (coreutils), tapi saya bisa melihat sekarang ini adalah paket terpisah .
rozcietrzewiacz
@rozcietrzewiacz realpathtanggal kembali dari sebelumnya readlink -f(dan bahkan readlink, IIRC) berada di GNU coreutils (ada beberapa alat serupa di sekitar. readlink -fakhirnya menjadi standar de facto); realpathhanya disimpan untuk kompatibilitas dengan skrip yang masih menggunakannya.
Gilles 'SANGAT berhenti menjadi jahat'
Apa kelebihan $(dirname "$(which "$0")")di $(dirname $0)mana whichtidak ada lagi? Bukankah itu sama?
UlfR
readlink -ftampaknya tidak berfungsi di Mac OS X 10.11.6, tetapi realpathberfungsi di luar kotak.
Grav
9

Sistem saya tidak memiliki realpathseperti yang disarankan oleh rozcietrzewiacz .

Anda dapat melakukannya dengan menggunakan readlinkperintah. Keuntungan menggunakan ini daripada parsing whichatau solusi lain adalah bahwa bahkan jika bagian dari path atau nama file yang dijalankan adalah symlink, Anda akan dapat menemukan direktori di mana file sebenarnya berada.

MYDIR="$(dirname "$(readlink -f "$0")")"

File teks Anda kemudian dapat dibaca ke dalam variabel seperti ini:

TEXTFILE="$(<$MYDIR/textfile)"
Caleb
sumber
@rozcietrzewiacz: Saya sebenarnya tidak merujuk hanya whichsaran Anda . Solusi normal untuk ini melibatkan adil dirnameatau kombinasi dari cddan pwddalam subkulit. Readlink memiliki keunggulan di sini. realpathSepertinya cukup banyak hanya menjadi pembungkus readlink -f.
Caleb
Saya tidak tahu bagaimana realpathbedanya readlink -f. Saya hanya bisa melihatnya memberi saya hasil yang sama (berlawanan dengan which).
rozcietrzewiacz
Perlu diingat bahwa readlink -f(dari GNU coreutils) TIDAK memerlukan elemen terakhir dari path untuk ada, readlink -etidak, tetapi tidak didukung oleh busybox readlink, yang meniru perilaku -edalam -fpilihan mereka .
dragon788
8

$0di skrip akan menjadi path lengkap ke skrip, dan dirnameakan mengambil path lengkap dan memberikan Anda hanya direktori, sehingga Anda dapat melakukan ini ke cat textfile:

$ cat "$(dirname -- "$0")/textfile"
Michael Mrozek
sumber
Meskipun ini tampaknya berhasil tanpa realpath $0, Anda salah mengatakan bahwa " $0dalam skrip akan menjadi jalan penuh ke skrip".
rozcietrzewiacz
@ OZ Dengan cara apa?
Michael Mrozek
1
$0adalah perintah sebagaimana dijalankan, yang bisa mis ../script.sh.
rozcietrzewiacz
Jadi, sebenarnya $(dirname "$0")mengembalikan path relatif ke skrip, sebagai bagian dari perintah yang dipanggil - bukan path absolut. Ini dapat menyebabkan masalah dalam skrip yang mengubah direktori saat berjalan.
rozcietrzewiacz
@roz Ah, menarik. Jadi saya kira itu tidak akan menimbulkan masalah di sini karena dia memanggil sesuatu di jalan dengan nama, tapi itu akan merusak hal-hal lain. Terima kasih
Michael Mrozek
4

Anda dapat meletakkan ini di bagian atas skrip Anda:

cd "${BASH_SOURCE%/*}" || exit

Variabel bash internal BASH_SOURCE sebenarnya adalah array nama path. Jika Anda mengembangkannya sebagai string sederhana, misalnya "$ BASH_SOURCE", Anda akan mendapatkan elemen pertama, yang merupakan pathname dari fungsi atau skrip yang sedang dijalankan.

Sumber: http://mywiki.wooledge.org/BashFAQ/028

David Kennedy
sumber
2

Saya sedang mencoba ini dan jalan tidak bekerja untuk saya. Solusi yang saya gunakan adalah:

SCRIPTDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )

Sejauh ini yang bekerja dengan baik. Saya ingin tahu apakah ada potensi masalah dengan pendekatan tersebut.

Brettski
sumber
1
Bagus, tetapi tidak mengikuti symlinks. Coba ini:SCRIPT_DIR="$( cd "$(dirname "$( readlink -f ${BASH_SOURCE[0]} )")" >/dev/null 2>&1 && pwd)"
OronNavon
1

Saya menggunakan:

#! /bin/sh -
dir=$(cd -P -- "$(dirname -- "$0")" && pwd -P) || exit
dosomethingwith "${dir%/}/some-file"

Yang POSIX dan harus bekerja selama dirname dari $0tidak berakhir pada karakter baris baru, tidak -dan $CDPATHtidak diatur (dan mungkin beberapa kasus sudut lainnya jika skrip tidak dicari $PATH).

Stéphane Chazelas
sumber
0

Saya selalu menggunakan whichuntuk menemukan path lengkap dari executable dari PATH. Contohnya:

which python

Jika Anda menggabungkan ini dengan dirnameperintah maka Anda mendapatkan:

wp=`which python`
dn=`dirname $wp`
ls $dn
Michael Dillon
sumber