例如,如果我有文件 hello.c,其中仅包含:
int main() {
printf("Hello world");
return 0;
}
我用 gcc 构建了它,gcc hello.c -o hello
然后我就可以运行./hello
它了。
但是,如果我尝试使用 eg 从网络下载二进制文件curl
,我首先必须使用 chmod 设置权限,然后才能运行它。有理由吗? gcc 和/或curl 是否对文件设置了一些默认权限?
答案1
如何curl
知道该文件是可执行的?从技术上来说,它可以检查其内容,但这远远超出了curl
预期的范围。
默认权限由umask
(http://en.wikipedia.org/wiki/Umaskumask
)并且在从程序派生的权限之上可以添加可执行位(或完全使用不同的权限)。例如,gcc
知道它正在生成可执行文件,因此设置 exec 位。另一方面,curl
并不意味着创建可执行文件,因此仅使用默认权限。
答案2
当您通过 HTTP 下载文件时,您只会收到文件的内容,而不会收到其元数据,例如创建日期、权限等。
使用包含此元信息的不同协议,或者,如果您有权访问服务器,请在包含元数据信息的容器(例如 tar 文件)中提供文件。
如果这是一个严重的反复出现的挫败感,您还可以编写一个包装器,curl
尝试猜测正确的权限并在下载完成时设置它们(提示:file
猜测文件类型)。
答案3
在unix系统中,一个文件是否可执行仅取决于它的权限,而不是它的名称或内容。 (如果文件格式不是有效的可执行文件,系统将尝试执行并将其视为执行程序时可能出现的错误之一,以及资源不足、缺少库等)
您从网络下载的大多数文件并不意味着可执行,因此curl 不会尝试使文件可执行。即使该文件本来要执行,您现在可能不想执行它;例如,您可能想要对其进行审查,并且仅在通过审查后才使该文件可执行。
另一方面,gcc 或任何其他编译器旨在生成可执行程序,因此它会采取必要的步骤也就不足为奇了。对于 gcc,这是编译过程的最后阶段之一。你可以观察它斯特雷斯:
$ strace -f gcc a.c
…
23429 execve("/usr/bin/ld", ["/usr/bin/ld", "--eh-frame-hdr", "-m", "elf_i386", "--hash-style=both", "-dynamic-linker", "/lib/ld-linux.so.2", "-z", "relro", "/usr/lib/gcc/i486-linux-gnu/4.3."..., "/usr/lib/gcc/i486-linux-gnu/4.3."..., "/usr/lib/gcc/i486-linux-gnu/4.3."..., "-L/usr/lib/gcc/i486-linux-gnu/4."..., "-L/usr/lib/gcc/i486-linux-gnu/4."..., "-L/usr/lib/gcc/i486-linux-gnu/4."..., "-L/lib/../lib", ...], [/* 82 vars */]) = 0
…
23429 chmod("a.out", 0755) = 0
23429 exit_group(0) = ?
…
换句话说,链接器,这是编译的最后一个阶段并生成可执行文件,作为最后一步将输出文件的权限更改为可执行。
答案4
- “二进制”与“可执行文件”不同。将文件指定为“二进制”只是一种启发式方法,这意味着文件的内容通常不可读。将文件指定为“可执行文件”意味着它包含某种可以“运行”的程序(即使是非二进制形式,例如 shell 脚本)。无数的二进制格式只是数据容器。
- 您的命令生成的二进制文件
gcc
是总是将是一个主要用作可执行文件的文件。 - 您不能信任来自互联网的文件。不要试图猜测一个文件是否应该可执行,无论如何这是不可能的,因为即使是散文也可以用作 shell 脚本,
curl
而其他程序将简单地应用umask
并将任何内容留给gun.shoot(self.foot)
用户。