Singkat cerita: Saya ingin melacak cara beberapa executable dipanggil untuk melacak beberapa perilaku sistem. Katakanlah saya memiliki executable:
/usr/bin/do_stuff
Dan itu sebenarnya dipanggil oleh sejumlah nama yang berbeda melalui symlink:
/usr/bin/make_tea -> /usr/bin/do_stuff
/usr/bin/make_coffee -> /usr/bin/do_stuff
dan seterusnya. Jelas, do_stuff
akan menggunakan argumen pertama yang diterimanya untuk menentukan tindakan apa yang sebenarnya diambil, dan sisa argumen akan ditangani dengan mempertimbangkan itu.
Saya ingin merekam panggilan ke /usr/bin/do_stuff
(dan daftar lengkap argumen). Jika tidak ada symlink, saya hanya akan pindah do_stuff
ke do_stuff_real
dan menulis skrip
#!/bin/sh
echo "$0 $@" >> logfile
/usr/bin/do_stuff_real "$@"
Namun, seperti yang saya tahu bahwa itu akan memeriksa nama yang dipanggil, ini tidak akan berhasil. Bagaimana cara menulis skrip untuk mencapai yang sama tetapi masih meneruskan ke do_stuff
'nama yang dapat dieksekusi'
Sebagai catatan, untuk menghindari jawaban pada baris berikut:
- Saya tahu bahwa saya bisa melakukannya dalam C (menggunakan execve), tetapi akan jauh lebih mudah jika saya bisa, dalam hal ini, cukup gunakan skrip shell.
- Saya tidak bisa begitu saja mengganti
do_stuff
dengan program logging.
sumber
sh
, Anda bisa menggunakanmybase=${0##*/}
bukannya nama.basename
Doa sepertibasename -- foo.bar
tidak saya kenal, dan pada sistem Linux saya mengujinya menghasilkan hasilfoo.bar
yang akan memecahkan skrip. Apakah Anda yakin itu metode yang umum?basename -- foo.bar
pengembalianfoo.bar
,basename -- --foo--/bar
pengembalianbar
seperti yang diharapkan.basename "$foo"
hanya berfungsi jika Anda dapat menjamin$foo
tidak dimulai dengan a-
. Sintaks umum untuk menjalankan perintah dengan argumen arbitrer adalahcmd -x -y -- "$argument"
.cmd "$argument"
salah kecuali maksudmucmd "$option_or_arg"
. Sekarang, beberapa perintah (termasuk beberapa implementasi historisbasename
) tidak mendukung--
sehingga Anda terkadang harus memilih antara portabilitas dan keandalan.Anda dapat menggunakan
exec -a
(seperti yang ditemukan dalambash
,ksh93
,zsh
,mksh
,yash
tapi tidak POSIX belum) yang digunakan untuk menentukanargv[0]
perintah yang sedang dieksekusi:Perhatikan bahwa
$0
adalah tidak yangargv[0]
bahwa perintah menerima. Ini adalah jalur skrip sebagaimana diteruskan keexecve()
(dan yang diteruskan sebagai argumenbash
), tetapi itu mungkin cukup untuk tujuan Anda.Sebagai contoh, jika
make_tea
dipanggil sebagai:Seperti yang biasanya dilakukan shell ketika menjalankan perintah dengan nama (mencari executable in
$PATH
), wrapper akan:Itu bukan:
tapi itu cukup baik karena
do_stuff_real
tahu itu dimaksudkan untuk membuat teh.Di mana itu akan menjadi masalah adalah jika
do_stuff
dipanggil sebagai:karena itu akan diterjemahkan ke:
Itu tidak akan terjadi selama operasi normal, tetapi perhatikan bahwa pembungkus kami melakukan sesuatu seperti itu.
Pada kebanyakan sistem,
argv[0]
sebagai diteruskan ke script hilang setelah juru (di sini/bin/bash
) dijalankan ( yangargv[0]
dari interpreter pada kebanyakan sistem adalah jalan yang diberikan pada baris dia-bang ) sehingga tidak ada script shell dapat lakukan tentang hal itu.Jika Anda ingin meneruskannya
argv[0]
, Anda harus mengkompilasi executable. Sesuatu seperti:sumber
perl
ataupython
jika tersedia. Versi yang lebih lamazsh
tidak mendukungexec -a
, tetapi Anda selalu dapat menggunakannyaARGV0=the-argv-0 cmd args
.zsh
(meskipun sekarang Anda sudah menjelaskan bahwa Anda belum) tetapi itu terlalu tua, Anda masih bisa menggunakannya diARGV0
sana.