是否有任何 Unix/Linux 文件系统可以执行以下操作?
- 如果该文件是可执行的,则返回一个包含通过执行该文件生成的虚拟文件
stdout
(我想它必须是不可写的); - 否则与 ext4 及其朋友的行为相同并提供文件本身。
我最近遇到了一种情况,我无法将信息传递到进程中,但必须传递(多行)文件作为选项。在我看来,能够动态生成该文件(本地或通过网络)似乎是一个优雅的选择。
在 /tmp 上创建文件不是一个选项,因为该选项位于 LDAP 条目的属性中。我的 LDAP 条目包含一个类似于以下的属性值,它是静态定义的:
-fstype=cifs...,rw,credentials=FILENAME,... ://remote
它作为数据传递给对其进行评估的进程,并期望 FILENAME 作为选项的参数credentials=
。没有 Bash 或任何其他脚本。我无法知道在 LDAP 中动态创建 /tmp 文件。
请不要问为什么我想这样做:我通过解决方法解决了我的问题,但我仍然对基本问题感兴趣。
当然,这类事情总是伴随着额外的问题:它能安全地完成吗?
史蒂夫
答案1
好的,让我们看看我是否正确:您在 LDAP 中有一些数据,它们引用了一些文件名(以及其他内容)。假设该文件位于某个网络共享上,所有使用该 LDAP 目录的主机都可以读取该文件,并且您希望动态创建该文件的内容。因此,例如目录包含credentials=/ldap/foo.cred
,当某些系统打开时/ldap/foo.cred
,它们会获取动态数据。
好像有一个程序叫脚本文件, AFUSE(用户空间中的文件系统)实现几乎完全符合您的要求,但我不熟悉该工具,也不知道它的工作原理如何。 (@KamilMaciorowski 在评论和他们的文章中提到了这一点回答在超级用户上。)
ScriptFS 是一种新的文件系统,它仅复制本地文件系统,但会根据执行结果替换所有检测为“脚本”的文件。
FUSE,顾名思义,允许用户空间程序像其他任何程序一样实现文件系统,并且内核将文件访问请求安排到负责处理文件系统的进程。这将允许生成任意动态内容。据推测,它也可以通过网络共享工作,因为这些文件显示为常规文件,但我没有使用它的个人经验。
在更“传统”的功能中,最接近的功能是命名管道和命名套接字。
使用创建的命名管道mkfifo
类似于您在创建时使用的管道somecmd | grep foo
,只不过它们在文件系统中有一个名称并且可以从那里打开。所以你可以写mkfifo p; somecmd > p & grep foo < p
.或者类似地,读者可以先打开它。读者和作者都会阻塞,直到另一端有人为止。起初,这似乎可以做你想做的事情,你可以安排一个程序在管道上写入,并在有人打开它进行读取时给出当前输出。然而,管道只存在一次,因此并发用户将附加到同一个流。另外,我完全不知道它们如何通过网络共享工作。该管道可能仅存在于客户端,因此两端需要位于同一系统上。
Unix 域套接字也可以在文件系统中以名称存在(如果您正在运行 systemd,您可能可以在 下找到一些/run
)。连接时,打开的进程会连接到在套接字上侦听的进程(与 TCP 连接一样)。这里的连接是独立的,但问题是(据我所知)Unix 域套接字不能用 打开open()
,但需要用 连接connect()
。因此,你不能这样做cat < socket
,它不会起作用。
答案2
不。而且这样的文件系统毫无用处。
例如:如果sed
在该文件系统上,会如何ls | sed 's/a/b'
工作? shell 将打开sed
执行,但文件系统将返回 STDOUT sed
。但是,文件系统没有 STDIN sed
,因此,现在一切都挂起(sed
等待 STDIN)或退出(空 STDIN sed
)而不执行任何操作。
这也是一个XY问题。
您不应尝试通过更改文件系统行为来解决脚本问题。
正如 @Arkadiusz Drabczyk 所建议的,您的问题可以通过进程替换来解决。举个例子:如果你想做
sort file1 | uniq >tmp1
sort file2 | uniq >tmp2
diff tmp1 tmp2
但您不能或不想创建临时文件,tmp1
并且tmp2
您可以
diff <(sort file1 | uniq) <(sort file2 | uniq)
另一个例子,这看起来有点像你的问题:假设我有一个文件inputfile
:
a:b:c:d
i:j:k:l
e:f:g:h
我有一个简单的演示脚本:
#!/bin/bash
filename=$(echo $* | sed 's/.*credentials=//;s/,.*//')
echo "The filename is: $filename"
echo "The contents is:"
cat $filename
然后,显然,我可以:
./procsub.sh -fstype=cifs...,rw,credentials=inputfile,,... ://remote
输出将是:
a:b:c:d
i:j:k:l
e:f:g:h
但是,如果我想要对输出进行排序,我也可以这样做:
./procsub.sh -fstype=cifs...,rw,credentials=<(sort inputfile),,... ://remote
然后输出将是:
The filename is: /dev/fd/63
The contents is:
a:b:c:d
e:f:g:h
i:j:k:l
希望能澄清一点。
答案3
从语义上讲,您所描述的内容没有多大意义 - 使用 FUSE 构建起来相对简单 - 但在很多层面上它似乎都是错误的。
您希望能够从文件中读取潜在的动态数据,因为这是您无法修改的程序唯一从中获取数据的来源。这可以通过文件系统管道来解决:
#!/bin/bash
PIPE="/tmp/credentials"
if [ ! -p "$PIPE" ] ; then
mkfifo "$PIPE"
fi
do
echo $SECRET >$PIPE
done