在 Linux 中,有 7 种文件类型:(参考 -https://en.wikipedia.org/wiki/Unix_file_types)
- 常规文件
- 目录
- 块(缓冲)文件
- 字符(无缓冲)文件
- 管道(命名管道、先进先出)文件
- 指向文件或目录的符号链接
- 套接字文件
( * 对于符号链接类型,它可以链接到所有七种类型。)
从基本的方式来看,常规文件和文件的符号链接可以作为程序获取和调用。
. regular_file_script.sh
regular_file_program
. symlink_to_regular_file_script.sh
symlink_to_regular_file_program
据我所知,目录和目录的符号链接不能用作源脚本或作为程序调用。
最近我发现可以使用管道文件作为源脚本。您可以创建一个管道文件并向其中写入脚本,然后在另一个终端中获取它。这是一个例子:
在 A 航站楼:
$ mkfifo /tmp/pipe_script.sh ; echo 'echo i am a pipe_script' > /tmp/pipe_script.sh
在 B 航站楼:
$ cat /tmp/test.sh
#!/bin/sh
echo sourcing a pipe script
. /tmp/pipe_script.sh
echo complete
$ /tmp/test.sh
sourcing a pipe script
i am a pipe_script
complete
然而,我发现一个管道文件不能作为程序直接调用。即使权限设置为755
,也会导致Permission denied
错误。例如:
在 A 航站楼:
$ mkfifo --mode 755 /tmp/pipe_program ; echo 'echo i am the pipe_program' > /tmp/pipe_program
在 B 航站楼:
$ cat /tmp/test.sh
#!/bin/sh
# echo sourcing a pipe script
# . /tmp/pipe_script.sh
echo call a pipe program
/tmp/pipe_program
echo complete
$ /tmp/test.sh
call a pipe program
/tmp/test.sh: line 6: /tmp/pipe_program: Permission denied
complete
为什么命名管道文件可以获取,但不能作为程序调用?
总而言之,在这七种类型中,哪些类型的 Linux 文件可以作为脚本获取或作为程序调用?
答案1
source
只要 BASH 能够读取,任何东西都可以被编辑,甚至是设备文件(如果权限正确)。
“程序”是一个完全不同的问题,除了普通文件之外,我没有听说过任何可以称为这个名称的东西。
符号链接很少用于运行应用程序。普通的 Linux 系统包含大量应用程序的硬链接,但符号链接通常是为共享库保留的。硬链接与普通文件没有区别,它们共享包括权限在内的所有内容。
答案2
正如其他人所说,任何可以读取的内容都可以由 shell 获取,或者通过管道传输到 shell 中。这也适用于其他一些口译员,例如Python。
然而,Linux 内核只会运行解析为常规文件的路径,可选地在解析符号链接之后。这间接记录在man execve
,这表明EACCES
如果返回(您看到的“权限被拒绝”错误)
该文件或脚本解释器不是常规文件。
execve
解析符号链接,但其他类似的系统调用可以配置为返回错误;看man execveat
和AT_SYMLINK_NOFOLLOW
。
您可以看到对常规文件的最后一次显式检查在do_open_execat
内核中:
/*
* may_open() has already checked for this, so it should be
* impossible to trip now. But we need to be extra cautious
* and check again at the very end too.
*/
err = -EACCES;
if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode) ||
path_noexec(&file->f_path)))
goto exit;
答案3
无法将管道作为可执行文件运行的最明显原因是它不支持随机访问。
执行文件涉及:
- 内核打开文件,并读取文件头的几个字节。
- 根据标头字节,它决定可执行文件的类型,并分派正确的二进制格式模块来进一步处理程序。
- 最终,可执行文件被处理给用户空间解释器,它想要再次打开文件并读取整个标头。
如果文件是 FIFO,则解释器无法再次打开该文件并读取相同的内容。每次打开 FIFO 进行读取时,都会生成一个会合使用打开 FIFO 进行写入的写入器进行。 A新的创建管道对象,然后将其用于这两个进程进行通信。