我以为我对bash文件重定向有很好的了解,通常我会尽量避免“无用的使用cat ”,但是我在脚本中遇到了一些意外的行为,并且我想了解为什么会发生这种情况。
在bash脚本中,我执行:
somecommand < file1 > file2
我的期望是file1是安全的,并且以只读方式打开。在实践中,我发现file1可以被覆盖。这是怎么/为什么发生的,有没有办法避免这种情况的发生cat
?
如果按照我的想象可以正常工作(该过程最终以直接的rw文件描述符结尾?),似乎应该认为以这种方式重定向文件很危险,但是我从未见过这种行为。
在我的案例中添加一些细节:有问题的命令是sops,它在后台正在做一些GPG的工作。GPG密码提示有时会被†写入用于输入的文件中,并被覆盖。我使用的完整命令是:
sops --input-type json --output-type json -d /dev/stdin < ./secrets/file.json > ./secrets/file-decrypted.json
从那以后我切换到了cat file1 | sops.. > file2
,一切都按预期进行。我会说这是“对猫的无用用途”-但这似乎不再那么无用了!
这是由于/dev/stdin
(实际上/proc/self/fd/0
)是在Linux(和Cygwin,但通常不是其他系统)上实现的方式造成的。
在Linux上打开/dev/stdin
不是像执行a一样dup(0)
,它只是重新打开与fd 0上重新打开相同的文件。它不共享文件开放性说明的是0的fd是指(与只读模式),但得到一个完全无关的新打开的文件说明中规定,与模式open()
。
因此,如果在读写模式下sops -d /dev/stdin
打开/dev/stdin
并且fd 0在on上以只读方式打开/some/file
,则/some/file
它将以读写模式打开。
实际上,cmd /dev/stdin < file
与相同cmd file < file
。您会发现这/dev/stdin
只是与以下内容的符号链接¹ file
:
/tmp$ namei -l /dev/stdin < file
f: /dev/stdin
drwxr-xr-x root root /
drwxr-xr-x root root dev
lrwxrwxrwx root root stdin -> /proc/self/fd/0
drwxr-xr-x root root /
dr-xr-xr-x root root proc
lrwxrwxrwx root root self -> 73569
dr-xr-xr-x stephane stephane 73569
dr-x------ stephane stephane fd
lr-x------ stephane stephane 0 -> /tmp/file
drwxr-xr-x root root /
drwxrwxrwt root root tmp
-rw-r--r-- stephane stephane file
情况可能会变得更糟。如果使用O_TRUNCATE打开,则文件将被截断。如果fd 0指向管道的读取端并/dev/stdin
在只写模式下打开,则将获得管道的另一端。
但是使用:
cat file | cmd /dev/stdin
将防止cmd
覆盖,file
因为所有人cmd
都会看到管道。即使它确实以只写模式打开,它也无法返回到file
,它只能到达管道的写入端,而读取端唯一的文件描述符将是cmd
stdin。
其他操作系统没有问题,就像打开/dev/stdin
一样dup(0)
,因此您将获得相同的打开文件描述,并且如果使用不兼容的模式打开,则open()
系统调用只会失败。
¹从技术上讲,就像@ user414777在评论中指出的那样,/proc/<pid>/fd/<fd>
它们是魔术符号链接,例如,它们可以到达普通符号链接无法到达的位置,但是在打开它们时,经过路径解析阶段,它们的作用就像普通符号链接一样。您只需打开目标文件
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句