问题
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