在Bash脚本中,如果我执行echo "abc" > file.txt
或echo "abc" >> file.tx
,我保证在执行脚本的下一行时,"abc"
中会出现file.txt
?
澄清:
我的想法是,在我这样做之后能否确定
echo "some text" > file.txt
然后继续执行我的脚本中的下一行,并从我的脚本调用其他进程,该进程读取file.txt
,该进程是否会从文件中读取"some text"
?
此外,一旦我写了这样的文件并终止脚本,脚本终止执行刷新吗?
答案 0 :(得分:4)
一旦包含重定向到file.txt
的命令终止,写入stdout的任何内容都会出现在file.txt
中,并且会被后续进程看到file.txt
。
但有一些警告:
另一个同时执行的进程完全有可能删除或覆盖该文件。
Unix / Linux不保证在文件关闭时立即将写入文件的数据提交到永久存储器。 [注1]因此,如果存储文件的机器崩溃并在写入和读取之间重新启动,则读取任务可能无法在崩溃之前看到写入的数据。
如果写入任务异常终止,则可能无法将其输出缓冲区刷新到stdout。因此,如果任务崩溃,则可能没有任何内容写入文件。
总之,最好是说在bash命令过程中写入文件的数据(无论是直接命名还是通过重定向)只要第一个任务正常终止,就会对后续命令可见。其他正在运行的进程正在操作同一个文件,并且主机在执行后续命令之前不会崩溃。
通常情况下,文件没有立即提交到永久存储器并不重要,因为操作系统必须表现为文件中存在挂起的修改。此外,在正常关闭期间,操作系统将提交所有挂起的文件系统修改。但是,如果主机崩溃,或者在重新启动时出现一些不可恢复的文件系统错误,那么某些文件系统修改可能会丢失。
以上所有内容都适用于存储文件的机器,该机器可能与编写文件的机器不同,并且在通过网络文件系统访问文件的情况下读取。
答案 1 :(得分:1)
直接答案是是。如果您使用重定向输出启动的进程已完成(为此,shell只执行 wait(2)系统调用),则已从内核表中删除了完整的进程映像,并且所有文件描述符均为已关闭(因此无法再进行系统调用)。
通常,您无法保证进程在其用户空间中进行缓冲。内核保证,一旦执行了 write(2)系统调用,所有系统进程看到的文件内容都包含该数据。为了实现这一点,内核只是阻塞内核内存中的inode映像,以允许进程进行系统调用以编写内核分配的缓冲区,而不会受到可能同时发生的其他内核活动的干扰。当进程读取(2)或写入(2)时,这将授予对文件内容的独占访问权限。并且inode被阻塞用于整个系统调用(使调用成为原子)。之后,所有文件内容都会更新到其他进程。
在进程写入时锁定inode会保证写入系统调用将在其他事情发生之前完成,例如:
所有这些可能性(以及更多)都必须在内核代码中被贬低,以保证数据的一致性。
当你正在执行的过程完成时,答案是所有写入的数据都会对其他进程可见(它已被清除,因此无法生成新的(在关闭(2)之后 ,即使没有数据刷新到磁盘,也不会在写入(2)之后。
另一方面,您使用的示例并未完全适用于此处的说明:echo
通常是一个内部shell命令,由shell中的shell执行。用户空间。因此,这可能会使事情以不同的方式发生,因为进行系统调用的进程是shell,并且在命令之前没有 exit(2)。但即使在这种情况下,shell也可以生成一个新进程来执行这个重定向命令(而不是调用 exec(2)执行不同的命令),并且退出(2) 后执行它,所以所有文件描述符也将被关闭。这使得该示例也适用于此。
如果shell没有为命令生成新进程(也有这种情况,至少在 bash(1)中),行为看起来好像一个新进程已经生成,因此shell具有正确 close(2)文件描述符的可靠性。