Làm thế nào để in tên tập lệnh riêng trong mawk?


13

Trong bash $0chứa tên của tập lệnh, nhưng trong awk nếu tôi tạo tập lệnh có tên myscript.awk với nội dung sau:

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

và chạy nó, nó sẽ chỉ in "awk". Ngoài ra, ARGV [i] với i> 0 chỉ được sử dụng cho các đối số tập lệnh trong dòng lệnh. Vậy, làm thế nào để làm cho nó in tên của kịch bản, trong trường hợp này là "myscript.awk"?


Tôi đã thay đổi tiêu đề từ awk thành mawk vì tất cả các giải pháp đều yêu cầu gawk và không hoạt động với awk chung, và đặc biệt với mawk được sử dụng rộng rãi (ví dụ: mặc định trên Ubuntu)
cipper

Điều gì khiến bạn nghĩ mawklà mặc định trên Ubuntu? Trên máy ảo 15.04 của tôi, mặc định awkgawk. Trong khi mawk được cài đặt, nó không phải là mặc định.
terdon

1
Đó là một kịch bản awk nếu bạn gọi nó bằng awk -f myscript.awk. Tuy nhiên, điều này không liên quan đến vấn đề trong câu hỏi.
cipper

1
@EdMorton Đó là một awkkịch bản bởi vì nó bắt đầu bằng #!/usr/bin/awk -f. Shell script bắt đầu bằng #!/bin/sh(hoặc một cái gì đó tương tự).
Barmar

1
Tôi đã nói chuyện với các chuyên gia shell khác nhau và cố gắng có được câu trả lời dứt khoát về việc đó là kịch bản shell hay awk và đáng ngạc nhiên theo POSIX việc giải thích các tệp bắt đầu bằng #! không xác định và không có tên loại cụ thể. Mặc dù một số người gọi nó là "tập lệnh trình thông dịch băm" chứ không phải là tập lệnh shell hoặc awk, sự đồng thuận dường như được coi là tập lệnh awk mặc dù kernel (không phải shell) diễn giải dòng đầu tiên vì awk vẫn phải có khả năng phân tích dòng đầu tiên đó (như một nhận xét) và bạn có thể thực hiện nó bằng cách sử dụng awk -f file.
Ed Morton

Câu trả lời:


5

Với GNU awk 4.1.3 trong bash trên cygwin:

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

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

Tôi không biết nó di động như thế nào. Tuy nhiên, như mọi khi, tôi sẽ không thực thi tập lệnh awk bằng cách sử dụng shebang trong tập lệnh shell vì nó chỉ cướp đi chức năng có thể của bạn. Giữ cho nó đơn giản và chỉ cần làm điều này thay vào đó:

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

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

Điều cuối cùng sẽ làm việc với bất kỳ awk hiện đại trong bất kỳ shell nào trên bất kỳ nền tảng nào.


Lưu ý rằng cái đầu tiên chỉ hoạt động trong bash, zsh hoặc ksh. Sau này là về kịch bản shell, không phải kịch bản awk.
cuonglm

2
Cảm ơn bạn! ENVIRON["_"]hoạt động hoàn hảo, và nó không gọi bất kỳ chương trình bên ngoài. Tùy chọn thứ hai awk -v ...phụ thuộc vào cách người ta chạy tập lệnh; Tôi không muốn điều này.
cipper

1
Gọi kịch bản của bạn tst.shlà sai lệch. Đó là một awkkịch bản, không phải là một kịch bản shell. BEGINkhông phải là một lệnh shell hợp lệ.
Barmar

1
Đúng nhưng câu hỏi về tính di động không phải là "ENVIRON [] xách tay" nó "có ENVIRON["_"]tạo ra đường dẫn kịch bản lệnh gọi khi được in từ mọi awk được gọi qua một shebang từ mọi shell" không? Tôi sẽ không bao giờ gọi một kịch bản awk từ một shebang cho cá nhân tôi không quan tâm đến câu trả lời mà chỉ nghĩ rằng tôi đã đề cập đến nó .... Oh Tôi thấy trong các ý kiến ​​trên mà @cuonglm đã trả lời rằng nó chỉ được hỗ trợ trong một số shell .
Ed Morton

1
Điểm tốt, @Ed. Được xác minh là không thành công trong dấu gạch ngang (trả về lệnh trước đó (hoặc nếu không là chính vỏ) chứ không phải lệnh hiện tại). ksh93 thú vị tiền tố PID trong dấu hoa thị, ví dụ *12345*/tmp/test.awk. ARGV[0]đáng tin cậy luôn luôn awktrong dash, bash, zsh và ksh93.
Adam Katz

5

Tôi không nghĩ rằng điều này là có thể theo gawk tài liệu :

Cuối cùng, giá trị của ARGV[0](xem phần 7.5 Biến tích hợp) thay đổi tùy theo hệ điều hành của bạn. Một số hệ thống được đặt awkở đó, một số đặt tên đường dẫn đầy đủ của awk (chẳng hạn như /bin/awk) và một số đặt tên cho tập lệnh của bạn ('lời khuyên'). Đừng dựa vào giá trị của ARGV[0]việc cung cấp tên tập lệnh của bạn.

Trên linuxbạn có thể thử sử dụng một loại một bẩn hack và như chỉ trong ý kiến của Stéphane Chazelas nó là có thể nếu thực hiện awkhỗ trợ NUL byte:

#!/usr/bin/awk -f

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

kịch bản của bạn dường như không hoạt động. Nó chỉ in "k" nếu được gọi bằng "awk -f script.awk" và nó in "s" nếu được gọi bởi "
./script.awk

@cipper: Ở đây nó hoạt động với gawk và thất bại (như mô tả của bạn) với mawk. Hấp dẫn!

Nó hoạt động với tôi trong linux, awk- 4.0.2. Trong freebsd với /proc/curpoc/cmdline, vàawk kết quả giống như của bạn nhưng hoạt động với gawk.
Taliezin

Trên Ubuntu mặc định, nó không hoạt động. Nó sẽ là tốt đẹp để tìm một giải pháp di động.
cipper

1
@taliezin: câu trả lời của cuonglm không phải là một giải pháp vì nó yêu cầu phải tự cung cấp tập lệnh với tên của nó. Nó giống như gọi awk -vNAME="myscript.awk" ./myscript.awkvà sau đó in TÊN trong tập lệnh. Không phải là một giải pháp.
cipper

5

Tôi không biết bất kỳ cách trực tiếp nào để có được tên lệnh từ bên trong awk. Tuy nhiên, bạn có thể tìm thấy nó thông qua một vỏ phụ.

chim ưng

Với GNU awk và pslệnh, bạn có thể sử dụng ID tiến trình PROCINFO["PID"]để lấy tên lệnh làm cách giải quyết. Ví dụ:

cmdame.awk

#!/usr/bin/gawk -f

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

chim ưng và chim ưng

Bạn có thể sử dụng cùng một cách tiếp cận, nhưng rút ra được awkPID từ $PPIDbiến shell đặc biệt (PID của cha mẹ):

cmdame.awk

#!/usr/bin/mawk -f

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

Kiểm tra

Chạy đoạn script như thế này:

./cmdname.awk

Đầu ra trong cả hai trường hợp:

cmdname.awk

Tôi đã gặp lỗi: / bin / sh: 1: -o: không tìm thấy
cipper

@cipper: Điều này chỉ hoạt động với GNU awk, tôi đã thêm dòng shebang bị thiếu.
Thor

Từ hướng dẫn gawk : Theo POSIX, 'biểu thức | getline 'không rõ ràng nếu biểu thức có chứa các toán tử không được liên kết khác với' $ '- ví dụ:' "echo" "date" | getline 'không rõ ràng vì toán tử ghép không được ngoặc. Bạn nên viết nó dưới dạng '("echo" "date") | getline 'nếu bạn muốn chương trình của bạn có thể mang theo cho tất cả các triển khai awk.
cipper

1
Nếu nó cần gawknó là một gawkgiải pháp thay vì một awkgiải pháp. Tôi nghĩ rằng @cipper nên thêm mong muốn của mình "một giải pháp di động" vào câu hỏi.

1
@Thor: câu trả lời của cuonglm không phải là một giải pháp vì nó yêu cầu phải tự cung cấp tập lệnh với tên của nó. Nó giống như gọi awk -vNAME="myscript.awk" ./myscript.awkvà sau đó in TÊN trong tập lệnh. Không phải là một giải pháp.
cipper

4

Với POSIX awk:

#!/usr/bin/awk -f

BEGIN {
    print ENVIRON["AWKSCRIPT"]
}

Sau đó:

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

4
Bạn tự cung cấp tên của tập lệnh trong đó, đây không phải là cách tự in
cipper

@cipper: Chà, đó là cách dễ nhất và di động mà tôi có thể tưởng tượng.
cuonglm

2
Nó giống như gọi awk -vNAME="myscript.awk" ./myscript.awkvà sau đó in biến NAMEtrong tập lệnh. Không phải là một giải pháp.
cipper

@cipper: Đó là cách duy nhất, nếu bạn đề cập mawk. Và cũng sử dụng ENVIRONkhông giống như sử dụng -vNAME="myscript.awk", vì khi nào mawksẽ mở rộng chuỗi thoát trong NAME.
cuonglm

4

Sử dụng GNU awk

Kiểm tra hướng dẫn sử dụng GNU awk - 7.5.2 Các biến tích hợp truyền tải thông tin mà tôi tình cờ thấy:

QUY TRÌNH #

Các yếu tố của mảng này cung cấp quyền truy cập vào thông tin về chương trình awk đang chạy. Các yếu tố sau (được liệt kê theo thứ tự abc) được đảm bảo có sẵn:

PROCINFO ["pid"]

ID tiến trình của quy trình hiện tại.

Điều này có nghĩa là bạn có thể biết được chương trình PID trong thời gian chạy. Sau đó, vấn đề là sử dụng system()để tìm kiếm quy trình với PID đã cho này:

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

Tôi sử dụng ps -ef, hiển thị PID trên cột thứ 2. Giả sử thực thi được thực hiện thông quaawk -f <script> và không có tham số nào khác, chúng ta có thể giả sử trường cuối cùng của dòng chứa thông tin chúng ta muốn.

Trong trường hợp chúng tôi có một số tham số, chúng tôi sẽ phải phân tích dòng khác nhau - tốt hơn, sử dụng một số tùy chọn của ps để chỉ in các cột mà chúng tôi quan tâm.

Kiểm tra

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

Cũng lưu ý rằng một chương khác của hướng dẫn người dùng GNU awk cho chúng ta biết rằng ARGV không phải là hướng đi:

1.1.4 Chương trình awk có thể thực thi

Cuối cùng, giá trị của ARGV [0] (xem Biến tích hợp) thay đổi tùy theo hệ điều hành của bạn. Một số hệ thống đặt 'awk' ở đó, một số đặt tên đường dẫn đầy đủ của awk (chẳng hạn như / bin / awk) và một số đặt tên tập lệnh của bạn ('lời khuyên'). (dc) Đừng dựa vào giá trị của ARGV [0] để cung cấp tên tập lệnh của bạn.


Thật không may, PROCINFO chỉ là một tính năng gawk, không phải là awk chung. Ví dụ: nó không có sẵn trong mawk (được cài đặt theo mặc định trong
ubfox

Tôi biết ... Tại sao bạn lại gắn thẻ câu hỏi với [gawk]?
fedorqui

Bạn đúng. Khi tôi đăng câu hỏi, tôi không biết về tất cả những khác biệt giữa mawk và gawk. Thẻ đã thay đổi thành mawk bây giờ.
cipper

@cipper tốt :) Thực tế tôi đã thử nghiệm mawkvà không thể làm cho nó hoạt động được, vì vậy tôi đã cài đặt gawkvào Ubuntu của mình và nó đã hoạt động. Vì vậy, một cách giải quyết có thể được sử dụng gawk: D
fedorqui

1
@terdon, gawkkhông được cài đặt theo mặc định trên Ubuntu (hoặc ít nhất là một số phiên bản Ubuntu, nơi thực hiện mawkmặc định awk). IIRC, tôi cũng phải cài đặt nó trên Debian.
Stéphane Chazelas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.