我在RosettaCode页中发现了以下类型的shebang:
--() { :; }; exec db2 -txf "$0"
它适用于Db2,适用于Postgres。但是,我不了解整条线。
我知道双破折号是SQL中的注释,此后它使用一些参数将文件本身作为文件传递给Db2可执行文件。但是圆括号,卷曲的小节,冒号和分号又如何替换真正的shebang#呢??
我在RosettaCode页中发现了以下类型的shebang:
--() { :; }; exec db2 -txf "$0"
它适用于Db2,适用于Postgres。但是,我不了解整条线。
我知道双破折号是SQL中的注释,此后它使用一些参数将文件本身作为文件传递给Db2可执行文件。但是圆括号,卷曲的小节,冒号和分号又如何替换真正的shebang#呢??
Answers:
该脚本没有shebang / hashbang / #!
行,只是因为没有双破折号#!
。
但是,脚本将由Shell执行(请参见上面的链接的问题和解答),并且在该Shell中,如果-
函数名称中的有效字符是有效的,则该行将声明一个被称为--
不执行任何操作的Shell函数(嗯,它将运行:
,不执行任何操作),并且永不调用。
该函数以更常见的多行符号表示(只是为了使它看起来更明显,因为其奇数名称有点掩盖了它实际上是一个函数):
-- () {
:
}
函数定义的唯一目的是在shell脚本中有一条有效的行,同时有一条有效的SQL命令(注释)。这种代码称为多语言。
在声明了伪造的shell函数之后,该脚本在由shell脚本解释器执行时,将exec
用运行产生的进程替换当前的shell db2 -txf "$0"
,这db2 -txf
与在命令行中对脚本的路径名的使用相同。
此技巧可能无法在使用dash
或其他ash
基于外壳yash
的Bourne外壳ksh88
或ksh93
用作的系统上可靠地工作/bin/sh
,因为这些外壳不接受名称包含破折号的函数。
也相关:
我想以下内容也可以使用(未经实际测试):
--() { exec db2 -txf "$0"; }; --
正如@Kusalananda已经说过的那样,该技巧已被打破,并且无法在所有shell中使用。
这是我可移植的做法:
--/.. 2>/dev/null; exec db2 -txf "$0"
即使--
当前目录中存在一个名为的文件/目录,第一个命令也应该失败,并且任何错误都将由2>/dev/null
;然后,shell将继续执行第二个命令exec
。
ENOEXEC
在尝试执行时返回。尝试在下面运行脚本strace
以了解我的意思。
exec()
无法在外壳程序上运行,则该外壳程序应将脚本作为外壳程序脚本运行。“如果execl()函数由于等效于[ENOEXEC]错误的错误而失败,则shell将执行等效于命令的命令,该命令具有以命令名作为其第一个操作数的shell调用的方式,...”(请参见pubs.opengroup .org / onlinepubs / 9699919799.2018edition / utilities /…)
exec()
直接从非shell的东西访问它,它将无法正常工作。但是那会是什么情况呢?您可能想从中运行脚本cron
,但是我认为它还是通过外壳运行所有内容,即使不是,也可以很容易地拼写出来db2 -txf /path/to/script
,因为您只需要执行一次即可。在交互式shell上使用速记方式最有用。但是可以肯定的是,单独的包装器脚本可能更健壮。
echo 'int main(int c,char**a){execvp(a[1],a+1);}' | cc -include unistd.h -xc -; echo echo yeah > a.sh; chmod 755 a.sh; ./a.out ./a.sh; PATH=`pwd` ./a.out a.sh