Apakah ada perintah untuk menjalankan skrip sesuai dengan baris shebang-nya?

46

Jika saya ingin menjalankan skrip bash yang tidak memiliki set izin eksekusi, saya dapat melakukan:

bash script.sh

Apa yang harus saya gunakan alih-alih bashjika skrip tidak dapat dieksekusi dan saya tidak tahu penerjemah yang benar? Apakah ada perintah yang mencari penerjemah dari baris shebang dan menjalankan skrip dengannya?

Aivar
sumber
Apa yang salah dengan pesta?
steffen
@steffen, bagaimana Anda tahu file yang dimaksud adalah skrip bash?
muru
@muru mengutip dari Pertanyaan: "Jika saya ingin menjalankan skrip bash ..." Selain itu (bahkan jika itu bukan skrip bash), jika bash whateverberhasil, mengapa menggunakan sesuatu yang berbeda? bash tersedia di hampir setiap sistem * ix, jadi mengapa repot-repot ...
steffen
1
@steffen apakah Anda membaca sisa pertanyaan? Mereka berkata: "Jika ... maka saya bisa melakukan: ..." dan "Apa yang harus saya gunakan daripada bash jika ... Saya tidak tahu penerjemah yang benar ?"
muru
@uru: mungkin saya tidak melihat yang jelas. Tetapi jika file / memiliki / garis shebang, seperti yang dinyatakan dalam pertanyaan, bash akan melakukan apa yang diminta. Seperti yang akan perl, sesuai dengan jawaban di bawah ini. Jadi apa keuntungan dari tidak menggunakan bash?
steffen

Jawaban:

67

Ya. Ini disebut perl:

perl foo.bash    # works
perl foo.lua     # works
perl foo.clisp   # works
perl foo.csh     # works
perl foo.php     # works
perl foo.gnuplot # works (no arguments)
perl foo.pl      # works (obviously)
perl foo.py      # works
perl foo.sh      # works
perl foo.tcl     # works
perl foo.rb      # works
perl foo.nodejs  # works
perl foo.r       # works
perl foo.oct     # works
perl foo.csharp  # works (no arguments)

Ini disebutkan dalam dokumentasi Perl :

Jika #!baris tersebut tidak mengandung kata "perl" atau kata "indir", program yang dinamai setelah #!dijalankan bukan penerjemah Perl. Ini agak aneh, tetapi membantu orang-orang di mesin yang tidak melakukannya #!, karena mereka dapat memberi tahu program bahwa SHELL mereka adalah / usr / bin / perl, dan Perl kemudian akan mengirimkan program ke penerjemah yang benar untuk mereka.

Ole Tange
sumber
40
Yah, itu kotor sekali.
langsing
1
Apakah ekstensi file .jsjuga berfungsi?
Pysis
1
Juga, apa yang tidak dilakukan mesin #!. Saya sudah tampak beberapa lebih sekarang, dan belum mengalami masalah ini.
Pysis
1
Ok, itu hanya contoh Anda sepertinya menyoroti banyak ekstensi file, daripada menampilkan beberapa baris shebang dari file, dan saya kira saya berasumsi bahwa cara kerjanya diprediksi.
Pysis
2
Saya suka bagaimana man perlrunmalu-malu mengakui bahwa itu "sedikit aneh" :). Saya pikir ini harus diperlakukan sebagai rasa ingin tahu yang ditujukan pada lingkungan non-UNIX dan versi UNIX yang sangat lama.
langsing
25

Naskah tidak harus memiliki shebang

Jika skrip dijalankan dari interpreter, Anda tidak dapat memastikan ia memiliki shebang sama sekali . Script, jalankan dari interpreter tidak perlu shebang , jika Anda memanggil interpreter untuk menjalankan kode.

Karena itu jawabannya adalah tidak, tidak ada perintah yang akan mencari tahu dengan pasti apa bahasa (penerjemah) untuk menjalankan skrip. Namun Anda selalu dapat melihat ke dalam skrip dan melihat apakah ada shebang untuk mengetahuinya.

Singkatnya aturan:

  1. Saat Anda menjalankan skrip, memanggil penerjemah selalu mengesampingkan kemungkinan shebang, dieksekusi atau tidak, shebang atau tidak.
  2. Jika tidak dapat dieksekusi dan dijalankan dari interpreter, skrip tidak memerlukan shebang.
  3. Jika skrip dijalankan tanpa memanggil juru bahasa terlebih dahulu, ia membutuhkan (dan menggunakan) shebang untuk mengetahui juru bahasa yang akan dipanggil, dan harus dapat dieksekusi untuk memiliki "izin" untuk memanggil penerjemah dari shebang-nya.

Jika skrip tidak memiliki shebang, tidak ada informasi (langsung *) di dalam skrip untuk memberi tahu penerjemah apa yang akan digunakan.

Setelah mengatakan itu

Anda tentu saja selalu dapat menulis skrip pembungkus untuk mencoba mencari tahu apakah skrip tersebut memiliki shebang dan membaca interpreter dari itu, kemudian menjalankannya dari interpreter yang ditemukan.

Sebuah contoh

#!/usr/bin/env python3
import subprocess
import sys

args = sys.argv[1:]; script = args[0]

try:
    lang = open(script).readlines()[0].replace("#!", "").strip().split()[-1]
    cmd = [lang, script]+args[1:]
    subprocess.call(cmd)
except (PermissionError, FileNotFoundError, IndexError):
    print("No valid shebang found")
  • Simpan sebagai tryrundi $PATH(misalnya ~/bin, membuat direktori jika tidak ada, log out dan kembali), membuatnya dieksekusi . Kemudian jalankan:

    tryrun /path/to/nonexecutablescript

    panggilan (diuji) penerjemah yang benar pada skrip yang tidak dapat dieksekusi pythondan saya bash.

Penjelasan

  • Script hanya membaca baris pertama dari skrip, menghapus #!dan menggunakan sisanya untuk memanggil penerjemah.
  • Jika gagal memanggil juru bahasa yang valid, itu akan memunculkan a PermissionErroratau a FileNotFoundError.

Catatan

Ekstensi ( .sh, .pydll) tidak memainkan peran apa pun dalam menentukan penerjemah yang tepat di Linux.


(* Tentu saja memungkinkan untuk mengembangkan algoritma tebak "pintar" untuk menentukan sintaks dari kode.)

Yakub Vlijm
sumber
OK, jadi itu berarti meskipun Linux telah menerapkan ekstraksi shebang di suatu tempat (sehingga dapat memilih penerjemah yang benar untuk srcipts yang dapat dieksekusi), itu tidak disediakan sebagai perintah standar mandiri.
Aivar
@Aivar mengekstrak shebang bukan masalah, tetapi menjalankan kode tanpa itu sangat mungkin.
Jacob Vlijm
@Aivar Ah, saya mengerti maksud Anda. Jika skrip dapat dieksekusi dan dijalankan tanpa bahasa dalam perintah, skrip memanggil penerjemah, bukan sebaliknya.
Jacob Vlijm
1
@JacobVlijm Saya tidak akan mengatakan "skrip memanggil penerjemah", lebih seperti "kernel Linux mengambil baris shebang untuk mencari tahu penerjemah mana yang akan dipanggil saat menjalankan skrip".
Paŭlo Ebermann
@ PaŭloEbermann Terima kasih! Benar tentu saja. Kernel menangani seluruh prosedur dengan cara apa pun, tetapi secara kiasan, dan saya pikir lebih baik untuk memahami, adalah dengan mengatakan bahwa skrip "diizinkan" untuk menangani apa yang ditelepon juru bahasa (dan benar-benar melakukannya). Tidak yakin tentang kata-katanya, tetapi saya ingin menggambarkannya seolah-olah inisiatifnya ada pada skrip, sementara kernel benar-benar melakukan pekerjaannya.
Jacob Vlijm
6

Anda dapat mencapai ini dengan skrip seperti ini:

#!/bin/bash

copy=/tmp/runner.$$
cp $1 ${copy}
chmod u+x ${copy}
${copy}
rm ${copy}

Jadi:

$ echo "echo hello" > myscript
$ ./myscript
bash: ./myscript: Permission denied
$ ./runscript myscript 
hello

Saya merekomendasikan untuk tidak melakukan ini. Izin ada karena suatu alasan. Ini adalah program untuk menumbangkan izin.

Perhatikan bahwa penanganan shebang adalah fungsi kernel (dalam kode sumber Linux - fs/binfmt_script.c). Pada dasarnya proses yang memanggil skrip secara langsung tidak tahu #!- kernel menggunakannya untuk mengetahui bahwa ia perlu meluncurkan juru bahasa.

ramping
sumber
2
Saya selalu berasumsi itu adalah fungsi dari shell, BUKAN kernel. Belajar sesuatu yang baru hari ini.
boatcoder
1
@boatcoder - Karena Anda tertarik, tambahkan tautan ke tempat kode sumber Linux menanganinya.
langsing