why do `#!/usr/bin/env var=val command` gets into an infinite loop

試著忘記壹切 提交于 2019-12-23 18:29:53

问题


In man(1) env it say:

env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]

So consider print_A.sh:

#!/usr/bin/env A=b bash
echo A is $A

When I run it with ./print_A.sh it hangs.

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

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?


回答1:


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.

Part 1 - What's causing this?

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.

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.

Part 2 -- Why the endless loop?

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:

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).

Thus in the example, env is actually executed as /usr/bin/env 'A=b bash'script_name.

env thus does what it's told, sets the variable, and executes script_name. This again starts hashbang interpretation and we got our loop.



来源:https://stackoverflow.com/questions/33126309/why-do-usr-bin-env-var-val-command-gets-into-an-infinite-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!