Bagaimana cara mencetak nama skrip sendiri di mawk?


13

Di bash $0berisi nama skrip, tetapi awk jika saya membuat skrip bernama myscript.awk dengan konten berikut:

#!/usr/bin/awk -f
BEGIN{ print ARGV[0] }

dan jalankan, itu hanya akan mencetak "awk". Selain itu, ARGV [i] dengan i> 0 digunakan hanya untuk argumen skrip di baris perintah. Jadi, bagaimana cara membuatnya mencetak nama skrip, dalam hal ini "myscript.awk"?


Saya telah mengubah judul dari awk ke mawk karena semua solusi memerlukan gawk dan tidak bekerja dengan awk umum, dan khususnya dengan mawk yang banyak digunakan (misalnya default pada Ubuntu)
cipper

Apa yang membuat Anda berpikir mawkdefault di Ubuntu? Pada 15,04 VM saya, standarnya awkadalah gawk. Sementara mawk diinstal, itu bukan default.
terdon

1
Script awk jika Anda memanggilnya awk -f myscript.awk. Namun, ini tidak terkait dengan masalah yang dimaksud.
cipper

1
@ EdMorton Ini adalah awkskrip karena dimulai dengan #!/usr/bin/awk -f. Skrip shell dimulai dengan #!/bin/sh(atau yang serupa).
Barmar

1
Saya telah berbicara dengan berbagai pakar shell dan mencoba untuk mendapatkan jawaban yang pasti tentang apakah itu shell atau awk script dan secara mengejutkan menurut POSIX interpretasi file yang dimulai dengan #! tidak terdefinisi dan tidak memiliki nama tipe spesifik. Sementara beberapa orang menyebutnya sebagai "naskah interpreter hash bang" daripada skrip shell atau awk, konsensus tampaknya harus dianggap sebagai skrip awk meskipun kernel (bukan shell) menginterpretasikan baris pertama karena awk masih harus dapat menguraikan baris pertama itu juga (sebagai komentar) dan Anda dapat menjalankannya menggunakan awk -f file.
Ed Morton

Jawaban:


5

Dengan GNU awk 4.1.3 di bash on cygwin:

$ cat tst.sh
#!/bin/awk -f
BEGIN { print "Executing:", ENVIRON["_"] }

$ ./tst.sh
Executing: ./tst.sh

Saya tidak tahu seberapa portabel itu. Namun, seperti biasa, saya tidak akan menjalankan skrip awk menggunakan shebang dalam skrip shell karena hanya merampas kemungkinan fungsionalitas Anda. Tetap sederhana dan lakukan saja ini sebagai gantinya:

$ cat tst2.sh
awk -v cmd="$0" '
BEGIN { print "Executing:", cmd }
' "$@"

$ ./tst2.sh
Executing: ./tst2.sh

Yang terakhir akan bekerja dengan awk modern di shell apa pun di platform apa pun.


Perhatikan bahwa yang pertama hanya bekerja di bash, zsh atau ksh. Nantinya adalah tentang skrip shell, bukan skrip awk.
cuonglm

2
Terima kasih! ENVIRON["_"]berfungsi dengan baik, dan tidak memanggil program eksternal apa pun. Opsi kedua awk -v ...tergantung pada bagaimana seseorang menjalankan skrip; Saya tidak menginginkan ini.
cipper

1
Memanggil skrip Anda tst.shmenyesatkan. Ini sebuah awkskrip, bukan skrip shell. BEGINbukan perintah shell yang valid.
Barmar

1
Benar tetapi pertanyaan portabilitasnya bukan "apakah ENVIRON [] portable" itu "memang ENVIRON["_"]menghasilkan jalur skrip panggilan ketika dicetak dari setiap awk yang dipanggil melalui shebang dari setiap shell"? Saya tidak akan pernah memanggil skrip awk dari shebang karena saya pribadi tidak peduli dengan jawabannya tetapi hanya berpikir saya akan menyebutkannya .... Oh saya lihat di komentar di atas bahwa @cuonglm menjawab bahwa itu hanya didukung di beberapa shell .
Ed Morton

1
Poin bagus, @Ed. Diverifikasi sebagai gagal dalam dash (yang mengembalikan perintah sebelumnya (atau shell itu sendiri) daripada yang sekarang). ksh93 secara menarik mengawali PID dalam tanda bintang, misalnya *12345*/tmp/test.awk. ARGV[0]andal selalu awkdalam tanda hubung, bash, zsh, dan ksh93.
Adam Katz

5

Saya rasa ini tidak mungkin sesuai gawk dokumentasi :

Terakhir, nilai ARGV[0](lihat bagian 7.5 Variabel Internal) bervariasi tergantung pada sistem operasi Anda. Beberapa sistem meletakkan di awksana, beberapa menempatkan pathname penuh awk (seperti /bin/awk), dan beberapa meletakkan nama skrip Anda ('saran'). Jangan mengandalkan nilai ARGV[0]untuk memberikan nama skrip Anda.

Pada linuxAnda dapat mencoba menggunakan jenis peretasan yang kotor dan seperti yang ditunjukkan dalam komentar oleh Stéphane Chazelas , adalah mungkin jika implementasi awkdukungan NUL byte:

#!/usr/bin/awk -f

BEGIN { getline t < "/proc/self/cmdline"; split(t, a, "\0"); print a[3]; }

skrip Anda sepertinya tidak berfungsi. Ia hanya mencetak "k" jika dipanggil dengan "awk -f script.awk", dan ia mencetak "s" jika dipanggil oleh "./script.awk"
cipper

@cipper: Ini berfungsi gawkdan gagal (seperti uraian Anda) mawk. Menarik!

Ini berfungsi untuk saya di linux, awk- 4.0.2. Dalam freebsd dengan /proc/curpoc/cmdline, dan awkhasilnya seperti milik Anda tetapi bekerja dengannya gawk.
taliezin

Di ubuntu default tidak berfungsi. Akan menyenangkan untuk menemukan solusi portabel.
cipper

1
@taliezin: jawaban oleh cuonglm bukan solusi karena mengharuskan untuk memberi makan script secara manual dengan namanya. Ini seperti memanggil awk -vNAME="myscript.awk" ./myscript.awkdan kemudian mencetak NAMA di dalam skrip. Bukan solusi.
cipper

5

Saya tidak tahu cara langsung untuk mendapatkan nama perintah dari dalam awk. Namun Anda dapat menemukannya melalui sub-shell.

melongo

Dengan GNU awk dan psperintah Anda dapat menggunakan ID proses dari PROCINFO["PID"]untuk mengambil nama perintah sebagai solusinya. Sebagai contoh:

cmdname.awk

#!/usr/bin/gawk -f

BEGIN {
  ("ps -p " PROCINFO["pid"] " -o comm=") | getline CMDNAME
  print CMDNAME
}

mawk dan nawk

Anda dapat menggunakan pendekatan yang sama, tetapi mendapatkan awkPID dari $PPIDvariabel shell khusus (PID dari induk):

cmdname.awk

#!/usr/bin/mawk -f

BEGIN { 
  ("ps -p $PPID -o comm=") | getline CMDNAME
  print CMDNAME
}

Pengujian

Jalankan skrip seperti ini:

./cmdname.awk

Output dalam kedua kasus:

cmdname.awk

Saya mendapat pesan kesalahan: / bin / sh: 1: -o: not found
cipper

@cipper: Ini hanya berfungsi dengan GNU awk, saya menambahkan baris shebang yang hilang.
Thor

Dari manual gawk : Menurut POSIX, 'ekspresi | getline 'ambigu jika ekspresi mengandung operator yang tidak di-host selain' $ '- misalnya,' "echo" "date" | getline 'bersifat ambigu karena operator gabungan tidak di-kurung. Anda harus menuliskannya sebagai '("echo" "date") | getline 'jika Anda ingin program Anda portabel untuk semua implementasi awk.
cipper

1
Jika perlu gawkitu adalah gawksolusi, bukan awksolusi. Saya pikir @cipper harus menambahkan keinginannya "solusi portabel" ke pertanyaan.

1
@Thor: jawaban oleh cuonglm bukan solusi karena mengharuskan untuk memberi makan script secara manual dengan namanya. Ini seperti memanggil awk -vNAME="myscript.awk" ./myscript.awkdan kemudian mencetak NAMA di dalam skrip. Bukan solusi.
cipper

4

Dengan POSIX awk:

#!/usr/bin/awk -f

BEGIN {
    print ENVIRON["AWKSCRIPT"]
}

Kemudian:

AWKSCRIPT=test.awk ./test.awk
test.awk

4
Anda secara manual memasukkan nama skrip di dalamnya, ini bukan cara mencetak sendiri
cipper

@cipper: Ya, itu cara termudah dan portabel yang bisa saya bayangkan.
cuonglm

2
Ini seperti memanggil awk -vNAME="myscript.awk" ./myscript.awkdan kemudian mencetak variabel NAMEdi dalam skrip. Bukan solusi.
cipper

@cipper: Itulah satu-satunya cara, jika Anda menyebutkan mawk. Dan juga menggunakan ENVIRONtidak sama dengan menggunakan -vNAME="myscript.awk", karena kapan mawkakan memperluas urutan escape NAME.
cuonglm

4

Menggunakan GNU awk

Memeriksa panduan pengguna GNU awk - 7.5.2 Variabel Internal yang Menyampaikan Informasi yang saya temui:

PROCINFO #

Elemen-elemen dari array ini menyediakan akses ke informasi tentang program awk yang sedang berjalan. Elemen-elemen berikut (dicantumkan berdasarkan abjad) dijamin akan tersedia:

PROCINFO ["pid"]

ID proses dari proses saat ini.

Ini berarti bahwa Anda dapat mengetahui PID program saat runtime. Kemudian, itu adalah masalah menggunakan system()untuk mencari proses dengan PID yang diberikan ini:

#!/usr/bin/gawk -f
BEGIN{ pid=PROCINFO["pid"]
       system("ps -ef | awk '$2==" pid " {print $NF}'")
}

Saya menggunakan ps -ef, yang menampilkan PID pada kolom ke-2. Dengan asumsi eksekusi dilakukan melalui awk -f <script>dan tidak ada parameter lain, kita dapat mengasumsikan bidang terakhir dari baris berisi informasi yang kita inginkan.

Jika kita memiliki beberapa parameter, kita harus menguraikan baris secara berbeda -atau, lebih baik, gunakan beberapa opsi psuntuk mencetak hanya kolom yang kita minati.

Uji

$ awk -f a.awk 
a.awk
$ cp a.awk hello.awk
$ awk -f hello.awk 
hello.awk

Perhatikan juga bahwa bab lain dari panduan pengguna awk GNU memberi tahu kita bahwa ARGV bukanlah jalan yang harus ditempuh:

1.1.4 Program awk yang dapat dieksekusi

Akhirnya, nilai ARGV [0] (lihat Variabel Internal) bervariasi tergantung pada sistem operasi Anda. Beberapa sistem menempatkan 'awk' di sana, beberapa meletakkan pathname penuh awk (seperti / bin / awk), dan beberapa meletakkan nama skrip Anda ('saran'). (dc) Jangan mengandalkan nilai ARGV [0] untuk memberikan nama skrip Anda.


sayangnya PROCINFO hanyalah fitur gawk, bukan awk umum. Misalnya tidak tersedia dalam mawk (yang diinstal secara default di ubuntu)
cipper

Saya tahu ... Mengapa Anda menandai pertanyaan dengan [gawk]?
fedorqui

Kamu benar. Ketika saya memposting pertanyaan saya tidak menyadari semua perbedaan antara mawk dan gawk. Tag telah berubah menjadi mawk sekarang.
cipper

@cipper good :) Saya sebenarnya sedang menguji dengan mawkdan tidak bisa membuatnya bekerja, sehingga saya instal gawkdi Ubuntu saya dan itu berhasil. Jadi solusinya dapat menggunakan gawk: D
fedorqui

1
@terdon, gawktidak diinstal secara default di Ubuntu (atau setidaknya beberapa versi Ubuntu, di mana implementasi mawkdefault awk). IIRC, saya harus menginstalnya juga di Debian.
Stéphane Chazelas
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.