如何在mawk中打​​印自己的脚本名称?


13

在bash中$0包含脚本的名称,但是在awk中,如果我使用以下内容创建名为myscript.awk的脚本:

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

并运行它,它只会打印“ awk”。此外,i> 0的ARGV [i]仅用于命令行中的脚本参数。那么,如何使其打印脚本名称,在本例中为“ myscript.awk”?


我已将标题从awk更改为mawk,因为所有解决方案都需要gawk,并且不适用于一般awk,尤其是与广泛使用的mawk(例如,Ubuntu上的默认设置)一起工作
cipper

是什么让您认为mawkUbuntu上的默认设置?在我的15.04 VM上,默认awk值为gawk。安装mawk时,它不是默认设置。
terdon

1
如果通过调用,这是一个awk脚本awk -f myscript.awk。但是,这与所讨论的问题无关。
cipper

1
@EdMorton这是一个awk脚本,因为它以开头#!/usr/bin/awk -f。Shell脚本以#!/bin/sh(或类似的东西)开头。
Barmar 2015年

1
我一直在与各种shell专家进行交谈,并试图获得关于shell还是awk脚本的明确答案,并且令人惊讶地根据POSIX对以#开头的文件进行解释!未定义,没有特定的类型名称。尽管有些人将其称为“哈希爆炸解释器脚本”而不是shell或awk脚本,但共识似乎是,即使内核(而非shell)解释第一行,也应将其视为awk脚本,因为awk仍然还必须能够解析第一行(作为注释),您可以使用来执行它awk -f file
Ed Morton 2015年

Answers:


5

在cygwin的bash中使用GNU awk 4.1.3:

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

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

我不知道那有多便携。但是,与往常一样,我不会在shell脚本中使用shebang执行awk脚本,因为它只会抢劫您可能的功能。保持简单,只需执行以下操作即可:

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

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

最后一个可以在任何平台上的任何shell中与任何现代awk一起使用。


请注意,第一个仅适用于bash,zsh或ksh。后面的内容是关于shell脚本的,而不是关于awk脚本的。
cuonglm

2
谢谢!ENVIRON["_"]完美地工作,并且不调用任何外部程序。第二种选择awk -v ...取决于运行脚本的方式。我不要这个
cipper

1
调用脚本tst.sh会产生误导。这是一个awk脚本,而不是外壳脚本。BEGIN不是有效的Shell命令。
Barmar 2015年

1
是的,但是可移植性问题不是“ ENVIRON []是否可移植”,而是“ ENVIRON["_"]当从每个外壳通过shebang调用的每个awk打印时,是否会产生调用外壳脚本路径”?我永远不会从shebang调用awk脚本,我个人并不在乎答案,而只是以为我会提到它...。 。
Ed Morton

1
好点,@ Ed。验证为破折号失败(返回上一个命令(或外壳本身),而不是当前命令)。有趣的是,ksh93在PID前面加上星号,例如*12345*/tmp/test.awkARGV[0]可靠地始终awk是dash,bash,zsh和ksh93。
亚当·卡兹

5

我认为根据gawk 文档,这是不可能的:

最后,值ARGV[0](请参阅第7.5节内置变量)取决于您的操作系统。有些系统放在awk其中,有些放在awk的完整路径/bin/awk名下(例如),有些放在您的脚本名下(“ advice”)。不要依赖于ARGV[0]提供脚本名称的值。

linux你可以尝试使用一种肮脏的黑客的并且在评论中指出斯特凡Chazelas这是可能的,如果实施的awk支持NUL字节:

#!/usr/bin/awk -f

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

您的脚本似乎无法正常工作。如果使用“ awk -f script.awk”调用,则仅打印“ k”,如果通过“ ./script.awk”调用,则仅打印“ s”
cipper

@cipper:在这里它可以使用gawk,但失败(如您的描述)mawk。有趣!

它在Linux awk4.0.2中对我有效。在freebsd中/proc/curpoc/cmdlineawk结果与您一样,但可以使用gawk
taliezin 2015年

在默认的ubuntu上它不起作用。找到一个便携式解决方案将是一个不错的选择。
cipper

1
@taliezin:cuonglm的答案不是解决方案,因为它需要手动输入脚本的名称。就像调用awk -vNAME="myscript.awk" ./myscript.awk然后在脚本中打印NAME一样。没办法。
cipper

5

我不知道从awk中获取命令名称的任何直接方法。但是,您可以通过子外壳找到它。

高克

使用GNU awk和ps命令,您可以使用进程ID从中PROCINFO["PID"]检索命令名称,这是一种解决方法。例如:

cmdname.awk

#!/usr/bin/gawk -f

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

花胶和na

您可以使用相同的方法,但是awk$PPID特殊的shell变量(父代的PID)派生PID :

cmdname.awk

#!/usr/bin/mawk -f

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

测试中

像这样运行脚本:

./cmdname.awk

两种情况下的输出:

cmdname.awk

我收到一个错误:/ bin / sh:1:-o:找不到
cipper

@cipper:这仅适用于GNU awk,我添加了缺少的shebang行。
2015年

来自gawk手册根据POSIX,“表达式| 如果表达式包含非$的非括号运算符,则“ getline”是不明确的,例如,““ echo”“ date” | “ getline”是不明确的,因为串联运算符未加括号。您应该将其写为'(“ echo”“ date”)| getline”,如果您希望您的程序可移植到所有awk实现中。
cipper

1
如果需要,gawk它是gawk解决方案,而不是awk解决方案。我认为@cipper应该在问题中添加他的愿望“便携式解决方案”。

1
@Thor:cuonglm的答案不是解决方案,因为它需要手动输入脚本的名称。就像调用awk -vNAME="myscript.awk" ./myscript.awk然后在脚本中打印NAME一样。没办法。
cipper

4

使用POSIX awk

#!/usr/bin/awk -f

BEGIN {
    print ENVIRON["AWKSCRIPT"]
}

然后:

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

5
您在其中手动输入脚本的名称,这不是自动打印的方式
cipper

@cipper:好吧,这是我能想到的最简单和可移植的方式。
cuonglm

3
就像调用awk -vNAME="myscript.awk" ./myscript.awk然后NAME在脚本中打印变量一样。没办法。
cipper

@cipper:如果您提到的话,那是唯一的方法mawk。并且using ENVIRON也与using不同-vNAME="myscript.awk",因为when mawk会扩展中的转义序列NAME
cuonglm

4

使用GNU awk

查看GNU awk用户指南-7.5.2传达信息的内置变量我偶然发现:

进程号

该数组的元素提供对有关正在运行的awk程序的信息的访问。以下元素(按字母顺序列出)保证可用:

PROCINFO [“ pid”]

当前进程的进程ID。

这意味着您可以在运行时知道程序的PID。然后,只需使用system()给定的PID查找进程即可:

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

我使用ps -ef,它在第二列上显示PID。假设执行是通过完成awk -f <script>并且没有其他参数的,我们可以假设该行的最后一个字段包含我们想要的信息。

如果我们有一些参数,我们将不得不对行进行不同的解析-或者更好的是,使用某些选项ps仅打印我们感兴趣的列。

测试

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

还要注意,《 GNU awk用户指南》的另一章告诉我们,ARGV并非可行之路:

1.1.4可执行awk程序

最后,ARGV [0]的值(请参阅内置变量)取决于您的操作系统。一些系统在其中放置“ awk”,一些系统在其中放置awk的完整路径名(例如/ bin / awk),而另一些系统在其中放置脚本的名称(“ advice”)。(dc)不要依赖ARGV [0]的值来提供脚本名称。


不幸的是,PROCINFO只是gawk功能,不是一般的awk。例如,它在mawk中不可用(默认情况下在ubuntu中已安装)
cipper

我知道...您为什么用[gawk]标记问题?
fedorqui's

你是对的。当我发布问题时,我不知道mawk和gawk之间的所有这些差异。该标签现在已更改为mawk。
cipper

@cipper good:)实际上我正在测试mawk并且无法使其正常工作,因此我将其安装gawk在Ubuntu中并可以正常工作。因此可以使用一种解决方法gawk:D
fedorqui

1
@terdon,gawk默认情况下未安装在Ubuntu(或至少某些Ubuntu版本,这mawk是默认awk实现)上。IIRC,我也必须在Debian上安装它。
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.