为什么`#!/ usr / bin / env var = val命令'进入无限循环 [英] why do `#!/usr/bin/env var=val command` gets into an infinite loop
问题描述
在 man(1)env
它说:
env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]
所以考虑 print_A.sh
:
#!/usr/bin/env A=b bash
echo A is $A
当我运行它与 ./ print_A.sh
它挂起。
运行它与 strace。 /print_A.sh
我得到以下日志,重复:
Running it with strace ./print_A.sh
I get the following log, repeating:
execve("/path/to/print_A.sh", ["/path/to/print_A.sh"...], [/* 114 vars */]) = 0
uname({sys="Linux", node="my-host", ...}) = 0
brk(0) = 0x504000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2a95556000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=171528, ...}) = 0
mmap(NULL, 171528, PROT_READ, MAP_PRIVATE, 3, 0) = 0x2a95557000
close(3) = 0
open("/lib64/tls/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\305\30100\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1641152, ...}) = 0
mmap(0x3030c00000, 2330696, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x3030c00000
mprotect(0x3030d30000, 1085512, PROT_NONE) = 0
mmap(0x3030e2f000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x12f000) = 0x3030e2f000
mmap(0x3030e35000, 16456, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x3030e35000
close(3) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2a95581000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2a95582000
mprotect(0x3030e2f000, 16384, PROT_READ) = 0
mprotect(0x3030b14000, 4096, PROT_READ) = 0
arch_prctl(ARCH_SET_FS, 0x2a95581b00) = 0
munmap(0x2a95557000, 171528) = 0
brk(0) = 0x504000
brk(0x525000) = 0x525000
open("/usr/lib/locale/locale-archive", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=48529088, ...}) = 0
mmap(NULL, 48529088, PROT_READ, MAP_PRIVATE, 3, 0) = 0x2a95583000
close(3) = 0
如下所述, bang并不等同于在命令行上运行它,但仍然为什么会进入无限循环?
As commented below, running a command in a hash-bang is not equivalent to running it on the command line, but still, why does it go into an infinite loop?
推荐答案
这个答案的两个部分。已经在一个重复问题。然而,那里的答案解释了问题的根本原因,而不是实际发生的情况。
There two parts to this answer. One has already been given in a duplicate question. The answers there, however, explain the root cause for the problem, not what is actually going on.
第1部分 - 是什么原因?
Hashbang解析从未真正标准化。 这里是Sven Mascheck的一个很好的写作,其中还包括一个表与不同操作系统的行为。
Hashbang parsing has never been really standardized. Here is a very good writeup by Sven Mascheck, which also includes a table with the behavior for different operating systems.
该表显示例如Linux确实都在一个中引用,这意味着#!/ usr / bin / env A = b bash
执行 env
与'A = b bash'
作为第一个参数。
The table shows that e.g. Linux does all args in one, meaning that #!/usr/bin/env A=b bash
executes env
with 'A=b bash'
as first argument.
第2部分 - 为什么是无限循环?
发生什么事情是,执行 env
环境变量 A ='b bash'
,然后重新执行原始脚本。这导致内核再次重新解释hashbang,我们得到一个无尽的 env
-exec循环。
What happens is that, env
is executed, it sets the environment variable A='b bash'
and then re-executes the original script. This results in the kernel re-interpreting the hashbang again and we get an endless env
-exec loop.
之后有一点想法,问题变得很明显:
After a little thinking, the problem becomes quite obvious:
一个文件 test.sh
与第一行#/ bin / sh param
执行 / bin / sh
as '/ bin / sh''param' 'test.sh'
。脚本名称作为新的命令行参数(即 argv
)附加。
A file test.sh
with first line #!/bin/sh param
executes /bin/sh
as '/bin/sh' 'param' 'test.sh'
. The script name is appended as a new command line parameter (i.e. to argv
).
因此,在该示例中, env
实际执行为 / usr / bin / env'A = b bash'
script_name
。
Thus in the example, env
is actually executed as /usr/bin/env 'A=b bash'
script_name
.
env
设置变量,并执行 script_name
。这再次开始hashbang解释,我们得到了我们的循环。
env
thus does what it's told, sets the variable, and executes script_name
. This again starts hashbang interpretation and we got our loop.
这篇关于为什么`#!/ usr / bin / env var = val命令'进入无限循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!