是什么在Unix中生成“文本文件繁忙”消息?


137

什么操作会产生错误“文本文件忙”?我无法确切地说。

我认为这与我正在创建一个临时python脚本(使用tempfile)并从中使用execl有关,但是我认为execl会更改正在运行的文件。

Answers:


130

此错误表示其他进程或用户正在访问您的文件。使用lsof检查什么其他进程正在使用它。您可以kill根据需要使用命令将其杀死。


115
Text file busy具体而言,该错误与尝试在可执行文件执行时对其进行修改有关。这里的“文本”是指以下事实:正在修改的文件是正在运行的程序的文本段。这是一个非常特殊的情况,而不是您的答案似乎暗示的一般情况。即使这样,您的答案也不是完全错误的。
ArjunShankar 2014年

4
带有评论的答案似乎已经完成。
Penz

OP询问哪个操作会产生错误,而不是说明错误的含义。
WonderWorker

我认为unix假定文件是“文本文件”的事实是不合逻辑的,在我看来,这是一个二进制文件,提示了此错误。
费利佩·瓦尔德斯

1
@FelipeValdes该名称是半个世纪前的术语的历史名称。例如,在multics中,程序的文本段与链接段不同,甚至更早的人们也谈论二进制文本。stackoverflow.com/a/1282540/833300
jma,

30

自从我看到该消息已有一段时间了,但是它在System V R3或大约几十年前就已经很普遍了。那时,这意味着您无法在程序可执行文件运行时对其进行更改。

例如,我正在构建一个make称为的工作环境rmk,并且过了一段时间后它才得以自我维护。我将运行开发版本并使其构建新版本。要使其正常工作,必须使用替代方法:

gcc -g -Wall -o rmk1 main.o -L. -lrmk -L/Users/jleffler/lib/64 -ljl
if [ -f rmk ] ; then mv rmk rmk2 ; else true; fi ; mv rmk1 rmk

所以,为了避免与“文本文件忙”问题,构建创造了一个新的文件rmk1,然后移动老rmkrmk2(重命名是不是一个问题;取消链接为),然后搬到新建rmk1rmk

我已经有相当一段时间没有看到现代系统上的错误了……但是我并不经常使用程序来自我重建。


3
这是一个超级快速的复制器:echo -e '#include <unistd.h>\nint main(void){sleep (5);return 0;}' > slowprog.c && cc slowprog.c && cp a.out b.out && (./a.out &) ; sleep 1 && cp b.out a.out。在我的新Fedora上产生了错误消息“ cp:无法创建常规文件'a.out':文本文件正忙”。
ArjunShankar 2014年

3
当然,这个答案是正确的,并且得到+1。您可能要删除“已有一段时间”免责声明。
ArjunShankar 2014年

@ArjunShankar这是在现代Linux上的C复制,带有“直接”系统调用:stackoverflow.com/questions/16764946 / ... GCC现在只能覆盖正在运行的可执行文件,因为如果unlink默认情况下,它首先执行一个。
西罗Santilli郝海东冠状病六四事件法轮功


6

最小的可运行C POSIX复制示例

我建议您了解底层API,以更好地了解发生了什么。

sleep.c

#define _XOPEN_SOURCE 700
#include <unistd.h>

int main(void) {
    sleep(10000);
}

#define _XOPEN_SOURCE 700
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(void) {
    int ret = open("sleep.out", O_WRONLY|O_TRUNC);
    assert(errno == ETXTBSY);
    perror("");
    assert(ret == -1);
}

编译并运行:

gcc -std=c99 -o sleep.out ./sleep.c
gcc -std=c99 -o busy.out ./busy.c
./sleep.out &
./busy.out 

busy.out通过断言,并perror输出:

Text file busy

因此我们推断出该消息是在glibc本身中进行硬编码的。

或者:

echo asdf > sleep.out

使Bash输出:

-bash: sleep.out: Text file busy

对于更复杂的应用程序,您还可以使用strace以下命令进行观察:

strace ./busy.out

其中包含:

openat(AT_FDCWD, "sleep.out", O_WRONLY) = -1 ETXTBSY (Text file busy)

在Ubuntu 18.04和Linux内核4.15.0上进行了测试。

如果您unlink先出现错误,则不会发生

notbusy.c:

#define _XOPEN_SOURCE 700
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(void) {
    assert(unlink("sleep.out") == 0);
    assert(open("sleep.out", O_WRONLY|O_CREAT) != -1);
}

然后类似于上述内容进行编译和运行,这些断言就会通过。

这解释了为什么它适用于某些程序而不适用于其他程序。例如,如果您这样做:

gcc -std=c99 -o sleep.out ./sleep.c
./sleep.out &
gcc -std=c99 -o sleep.out ./sleep.c

即使第二个gcc调用正在写入,也不会产生错误sleep.out

快速strace显示GCC首先在写之前取消链接:

 strace -f gcc -std=c99 -o sleep.out ./sleep.c |& grep sleep.out

包含:

[pid  3992] unlink("sleep.out")         = 0
[pid  3992] openat(AT_FDCWD, "sleep.out", O_RDWR|O_CREAT|O_TRUNC, 0666) = 3

它不会失败的原因是,当您unlink重新写入文件时,它将创建一个新的索引节点,并为正在运行的可执行文件保留一个临时的悬挂索引节点。

但是,如果write没有unlink,那么它将尝试写入与正在运行的可执行文件相同的受保护inode。

POSIX 7 open()

http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html

[ETXTBSY]

该文件是正在执行的纯过程(共享文本)文件,oflag为O_WRONLY或O_RDWR。

男子2开

ETXTBSY

路径名是指当前正在执行的可执行映像,并且已请求写访问权限。


1
取消链接的理由是该文件不再可从该目录访问,但inode仍然存在,引用计数>0。如果重用该名称,则它是新inode中的新文件-如果您不首先取消链接,而是实际上是在尝试写入受保护的inode。
Penz

@Penz obrigado发表评论,Leandro。我还奇怪呢,反过来,没有给出一个错误,如果你尝试写没有unlink。Linux在第一次exec调用后是否会多次读取文件?
西罗Santilli郝海东冠状病六四事件法轮功

产生ETXTBSY的是inode保护。如果不取消链接,则任何写入都将受到文件执行保护的索引节点。使用unlink,您将获得一个不受保护的新inode。(不确定“受保护”是否是这里的术语,但这是个主意)
Penz


3

如果尝试phpredis在Linux机器上构建,则可能需要sleep在运行文件之前给它一些时间来使用命令完成对文件许可权的修改:

chmod a+x /usr/bin/php/scripts/phpize \
  && sleep 1 \
  && /usr/bin/php/scripts/phpize

我认为chmod在设置权限之前不会返回。那可能是文​​件系统问题。
Penz

这发生在正在构建的Docker映像内部。
Stephane

1
Docker有多个存储驱动程序,我想并不是所有的驱动程序都是完美的。
Penz

不过,对于构建docker映像时遇到此问题的人来说,这仍然是一个很好的提示。
Maciej Gol

2

不知道原因,但我可以快速轻松地解决。

在“ cat> shScript.sh”(粘贴,^ Z)然后在KWrite中编辑文件之后,我刚刚在CentOS 6上遇到了这种奇怪的情况。奇怪的是,该脚本没有明显的实例(ps -ef)执行。

我的快速解决方法是简单地访问“ cp shScript.sh shScript2.sh”,然后能够执行shScript2.sh。然后我都删除了。做完了!


您的问题是因为您暂停了该cat过程。下次使用^ D,而不是^ Z。
弗拉基米尔·潘捷列夫

非常正确的弗拉基米尔。谢谢!那就是我在DOS / CMD提示符下所做的。旧的习惯...此后再也没有发生过:)
ScottWelker

2

您可能会发现这在CIFS / SMB网络共享上更为常见。当其他人打开该文件时,Windows不允许写入该文件,即使该服务不是Windows(它可能是某些其他NAS产品),它也可能会重现相同的行为。潜在地,它也可能是与锁定/复制模糊相关的一些潜在的NAS问题的体现。


2

如果您正在通过ssh连接使用MobaXTerm之类的工具运行.sh,并且该工具具有自动保存实用程序来编辑本地计算机上的远程文件,则该文件将被锁定。

关闭并重新打开SSH会话即可解决该问题。


1

我的经验之一:

我总是通过反向工程更改Chrome的默认键盘快捷键。修改后,我忘了关闭Chrome并运行以下命令:

sudo cp chrome /opt/google/chrome/chrome
cp: cannot create regular file '/opt/google/chrome/chrome': Text file busy

使用strace,您可以找到更多详细信息:

sudo strace cp ./chrome /opt/google/chrome/chrome 2>&1 |grep 'Text file busy'
open("/opt/google/chrome/chrome", O_WRONLY|O_TRUNC) = -1 ETXTBSY (Text file busy)

0

fopen()在文件上使用时,我在PHP中遇到了这个问题,然后unlink()在使用它之前尝试了fclose()它。

不好:

$handle = fopen('file.txt');
// do something
unlink('file.txt');

好:

$handle = fopen('file.txt');
// do something
fclose($handle);
unlink('file.txt');

我猜在窗户上?在Linux系统中,通常可以让我们删除打开的文件-在目录中引用被消除,但数据(i节点)是弗雷德只有当引用河段数字0
朋兹

不,这是在Centos上。
dtbarne 2015年

如Penz所述,它在Linux 4.7.10上使用ext4文件系统对其进行了测试,并且未产生任何错误。文件已成功删除。也许dtbarne使用了一些特殊的文件系统。
k3a

在无业游民上运行此程序-可能是由于它是共享文件夹。
dtbarne

0
root@h1:bin[0]# mount h2:/ /x             
root@h1:bin[0]# cp /usr/bin/cat /x/usr/local/bin/
root@h1:bin[0]# umount /x
...
root@h2:~[0]# /usr/local/bin/cat 
-bash: /usr/local/bin/cat: Text file busy
root@h2:~[126]#

ubuntu 20.04, 5.4.0-40-generic
nfsd problem, after reboot ok

请不要仅将代码发布为答案,还请提供解释代码的作用以及如何解决问题的方法。带有解释的答案通常会更有帮助,而且质量更好,并且更有可能引起反对。
Mark Rotteveel
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.