Temukan lokasi skrip shell bersumber

8

Apakah mungkin skrip shell bersumber tahu lokasinya? Saya sudah membaca menentukan path ke shell script bersumber tapi jawaban fokus pada bashdan tcshdan gagal jika POSIX shell digunakan. $0juga bukan solusi dan menghasilkan hasil yang salah .

Suatu solusi tidak harus 100% andal. Tidak mungkin jalur tersebut berisi hard atau symlink.

# sourcing the script should yield the absolute path to the script
. somedir/thescript

# within “thescript”
-> /tmp/foo/bar/somedir

Beberapa latar belakang: Skrip adalah bagian dari aplikasi yang sudah ada yang berisi lusinan binari dalam bindirektori di lokasi yang diketahui (bervariasi per arsitektur) relatif terhadap skrip bersumber. Untuk menggunakan aplikasi, pengguna sumber skrip yang mendahului bindirektori ke PATH, sehingga biner aplikasi dapat dengan mudah dipanggil dalam shell saat ini (shell mana pun yang mungkin).

Marco
sumber
Harap periksa sekali tautan ini mungkin apa yang Anda cari paste.ubuntu.com/6242655
Rahul Patil
@RahulPatil Itu hanya bekerja pada bash dan sangat tidak dapat diport.
Marco
1
Saya cukup yakin bahwa jawabannya adalah tidak. Anda hanya menemukan metode khusus shell karena tidak ada metode portabel. Untuk apa Anda membutuhkan ini? Bisakah Anda memberi tahu pengguna skrip untuk melakukan sesuatu yang berbeda dari . /path/to/scriptseperti MARCO_DIR=/path/to; . $MARCO_DIR/scriptatau eval "$(/path/to/script)"? @RahulPatil BASH_SOURCEjelas khusus untuk bash.
Gilles 'SANGAT berhenti menjadi jahat'
@Gilles Seperti yang saya katakan, itu tidak harus sangat kuat. Tapi saya belum menemukan cara yang bahkan jauh bekerja dalam kasus paling sederhana di shell POSIX. (Jadi solusi untuk saat ini adalah bahwa penggunaan aplikasi ini membutuhkan salah satu kerang didukung.) Jangan ragu untuk mengirim “tidak ...” sebagai jawaban jika itu adalah jawabannya.
Marco
@Gilles Mengubah cara aplikasi diatur bukan merupakan opsi. Itu akan merusak instalasi. Itu sebabnya saya ingin membuat skrip lebih kuat tanpa mengubah cara namanya. Pada akhirnya hanya menetapkan PATH, jadi jika skrip gagal, fallback adalah untuk menemukan binari dan menambahkan path mereka ke lingkungan.
Marco

Jawaban:

9

Lokasi skrip bersumber tidak tersedia kecuali jika Anda menggunakan shell yang menawarkan ekstensi ke spesifikasi POSIX. Anda dapat menguji ini dengan cuplikan berikut:

env -i PATH=/usr/bin:/bin sh -c '. ./included.sh' | grep included

dimana included.shmengandung

echo "$0"
set

Di bash, nama skrip bersumber di $BASH_SOURCE. Dalam zsh (dalam mode kompatibilitas zsh, bukan dalam mode kompatibilitas sh atau ksh), itu dalam $0(perhatikan bahwa dalam suatu fungsi, $0adalah nama fungsi sebagai gantinya). Dalam pdksh dan dash, itu tidak tersedia. Di ksh93, metode ini tidak mengungkapkan solusi, tetapi path lengkap ke skrip yang disertakan tersedia sebagai ${.sh.file}.

Jika membutuhkan bash atau ksh93 atau zsh cukup baik, Anda dapat menggunakan potongan ini:

if [ -n "$BASH_SOURCE" ]; then
  this_script=$BASH_SOURCE
elif [ -n "$ZSH_VERSION" ]; then
  setopt function_argzero
  this_script=$0
elif eval '[[ -n ${.sh.file} ]]' 2>/dev/null; then
  eval 'this_script=${.sh.file}'
else
  echo 1>&2 "Unsupported shell. Please use bash, ksh93 or zsh."
  exit 2
fi

Anda dapat mencoba menebak lokasi skrip dengan melihat file apa yang dibuka oleh shell. Secara eksperimental ini tampaknya berfungsi dengan tanda hubung dan pdksh tetapi tidak dengan bash atau ksh93 yang setidaknya untuk skrip pendek telah menutup file skrip pada saat mereka mulai menjalankannya.

  open_file=$(lsof -F n -p $$ | sed -n '$s/^n//p')
  if [ -n "$open_file" ]; then
    # best guess: $open_file is this script
  fi

Script mungkin bukan file dengan deskriptor nomor tertinggi jika skrip tersebut bersumber di dalam skrip kompleks yang telah diputar dengan pengalihan. Anda mungkin ingin mengulang-ulang file yang terbuka. Ini tidak dijamin untuk tetap bekerja. Satu-satunya cara yang dapat diandalkan untuk menemukan skrip bersumber adalah dengan menggunakan bash, ksh93 atau zsh.


Jika Anda dapat mengubah antarmuka, maka alih-alih mencari skrip Anda, minta skrip Anda mencetak cuplikan shell untuk diteruskan ke evaldalam pemanggil. Inilah yang biasanya dilakukan skrip untuk mengatur variabel lingkungan. Ini memungkinkan skrip Anda ditulis secara independen dari keanehan konfigurasi penelepon dan konfigurasi penelepon.

#!/bin/sh
FOO_DIR=$(dirname -- "$0")
cat <<EOF
FOO_DIR='$(printf %s "$FOO_DIR" | sed "s/'/'\\''/g")'
PATH="\$PATH:$FOO_DIR/bin";
export FOO_DIR PATH
EOF

Di penelepon: eval "`/path/to/setenv`"

Gilles 'SANGAT berhenti menjadi jahat'
sumber
0

Menambahkan ke jawaban Gilles, Anda MUNGKIN bisa mendapatkan skrip shell ( if $0 = ash) melalui /proc/$$ interface. Saya tidak tahu seberapa akurat ini, tetapi /proc/$$/fd/11sepertinya selalu menunjuk ke skrip ini dengan abu BusyBox.

Memberikan ini sebagai jawaban potensial bagi mereka yang menemukan halaman ini (seperti juga saya).

Jawaban terakhir telah dihapus - jadi, klaim saya untuk pekerjaan ini diuji pada 4 platform HW yang berbeda (x86, ARM, XLP, dan powerpc). Semua memberikan jawaban yang sama pada fd / 11. Tautan baca dari /proc/$$/fd/11hasil skrip saya.

Andy

A. Kennedy
sumber