Alih-alih memiliki myprg
secara ajaib mendeteksi apakah itu digunakan dalam shebang, mengapa tidak membuatnya eksplisit dengan menggunakan bendera baris perintah (seperti -f
) untuk memberikannya file sebagai skrip?
Dari contoh Anda di komentar:
Dalam contoh teori kalk di atas.
calc PI + 1
harus mengembalikan 4,14159... Sekarang menambahkan dukungan untuk shebang (yaitu nama file sebagai parameter pertama) akan mengembalikan perhitungan yang terkandung ke dalam file.
Buat calc
ambil file skrip melalui -f
lalu buat skrip dengan:
#!/usr/local/bin/calc -f
$1 + 1
Katakanlah Anda menyebut file ini addone.calc
dan membuatnya dapat dieksekusi. Kemudian Anda dapat memanggilnya dengan:
$ ./addone.calc PI
4.141592...
Panggilan itu akan diterjemahkan menjadi doa /usr/local/bin/calc -f ./addone.calc PI
, jadi cukup jelas argumen mana yang merupakan file skrip dan mana yang merupakan parameter skrip.
Ini mirip dengan cara awk
dan sed
berperilaku.
Pendekatan serupa (tetapi berlawanan) adalah memiliki calc
ambil argumen file skrip secara default (yang menyederhanakan penggunaannya dengan shebang), tetapi tambahkan flag baris perintah untuk menggunakannya dengan ekspresi dari argumen. Ini mirip dengan bagaimana sh -c '...'
berfungsi.
Masalah sebenarnya adalah cara Anda mendesain sintaks baris perintah <mypgm>
. Alih-alih mencoba mendukung dua cara untuk menginterpretasikan argumennya, berikan dua cara untuk menyebutnya sebagai gantinya.
Perintah Shebang dimaksudkan sebagai mesin skrip yang menjalankan konten skrip Anda; mungkin bash
, perl
, atau apa pun, tetapi diharapkan itu dipanggil dengan nama file skrip untuk dieksekusi. Bagaimana bash
lakukan? Itu tidak menebak. Jika menemukan argumen yang tidak terlihat seperti opsi (atau argumen opsi), ia akan memperlakukannya sebagai skrip untuk dieksekusi; argumen setelah itu diteruskan ke skrip. Misalnya:
/bin/bash -x -e somename foo bar
Di sini, bash akan mencari file somename
dan coba jalankan sebagai skrip dengan argumen foo
dan bar
. Anda harus melakukan hal yang sama, karena Anda mungkin ingin menulis <mypgm> <myscript>
pada baris perintah suatu hari nanti.
Jika Anda ingin menggunakan <mypgm>
tanpa skrip sebagai default, Anda dapat meminta skrip untuk diteruskan dengan <mypgm> -f <myscript>
. Ini adalah bagaimana sed
melakukannya. Maka Anda akan menggunakannya dalam garis shebang seperti ini:
#!<mypgm> -f
Jika Anda ingin case skrip menjadi default, seperti dengan bash
dan perl
, buat opsi yang mengatakan "tidak ada skrip saat ini". Anda bisa menggunakan --
untuk ini, sehingga <mypgm> -- one two three
tidak mencoba menjalankan one
(atau apa pun) sebagai skrip. Dalam hal ini, baris shebang hanya akan berbunyi:
#!<mypgm>
Sekarang, saya perlu tahu kapan blabla dipanggil menggunakan shebang, atau tidak:
Di C, Anda bisa mendapatkan info itu melalui getauxval(AT_EXECFN)
, yang akan memberi tahu Anda nama asli yang dapat dieksekusi (yaitu argumen pertama diteruskan ke execve(2)
) [1].
Tapi string itu ditempatkan di memori segera setelah argumen baris perintah dan string lingkungan, di akhir [stack]
wilayah memori, sehingga dapat diambil langsung dari sana.
Misalnya, skrip perl berikut (beri nama foo.pl
), jika dibuat dapat dieksekusi dengan chmod 755 foo.pl
, akan mencetak ./foo.pl
saat dijalankan secara langsung dan /usr/bin/perl
saat dijalankan sebagai perl ./foo.pl
:
#! /usr/bin/perl
open my $maps, "/proc/self/maps" or die "open /proc/self/maps: $!";
my $se;
while(<$maps>){ $se = hex($1), last if /^\w+-(\w+).*\[stack\]$/ }
open my $mem, "/proc/self/mem" or die "open /proc/self/mem: $!";
sysseek $mem, $se - 512, 0;
sysread $mem, $d, 512 or die "sysread: $!";
print $d =~ /([^\0]+)\0+$/, "\n";
Pada kernel linux yang lebih baru (>=3.5), akhir lingkungan juga tersedia di /proc/PID/stat
(di kolom ke-51, seperti yang didokumentasikan di proc(5)
halaman manual).
#! /usr/bin/perl
open my $sh, "/proc/self/stat" or die "open /proc/self/stat: $!";
my @s = <$sh> =~ /\(.*\)|\S+/g;
open my $mem, "/proc/self/mem" or die "open /proc/self/mem: $!";
seek $mem, $s[50], 0;
$/ = "\0";
my $pn = <$mem> or die "readline: $!"; chomp $pn; print "$pn\n";
[1] Kernel Linux yang lebih baru dari 2.6.26 memperkenalkan entri vektor aux yang menunjuk ke sana (lihat komit), tetapi nama yang dapat dieksekusi tersedia di akhir tumpukan jauh sebelum itu (sejak linux-2.0 dari 1996).