概述

Text file busy, Linux 系统内核报出的错误之一, errno 26. 可以通过如下方式查看:

$ man error | grep busy
       EBUSY           Device or resource busy (POSIX.1)
       ETXTBSY         Text file busy (POSIX.1)

其中 ETXTBSY 就是这个错误.

也可以参考维基百科: errno.h

发生原因

Text file busy 会在如下情况下发生:

  • 尝试写入(write)一个正在被执行的文件.
  • 尝试执行(execute)一个正在被写入的文件.

英文如下:

This occurs when you try and write to a file that is currently being executed by the kernel, or execute a file that is currently open for writing.

refer: ETXTBSY

其中需要注意的是执行(execute)的含义. 一般不加以区分的时候, 可能会认为如下两种情况都叫做执行, 但是含义不尽相同:

# 此例执行的二进制文件是 example.sh
./example.sh

# 此例执行的二进制文件是 sh, 而 example.sh 只是一个参数会被读取
sh example.sh
  1. ./example.sh 这种方式是把 example.sh 当作二进制可执行文件执行, 只是如果该文件第一行存在 shebang 的话, 会被 Linux 内核识别出来, 然后会自动使用 exec 命令重新使用 shebang 中指定的可执行文件重新执行并替换当前进程.

    refer: How does the #! shebang work?

  2. sh example.sh 这种方式被执行的二进制文件实际上是 sh, 此时 example.sh 只是被当做一个参数传入, 然后 sh 会来读取 example.sh 的内容, 所以这个 shell 脚本本身并没有被执行.

    refer: Why does behavior of './example' and 'sh example' different?

验证

上面提到出现 Text file busy 的原因有两种, 那么我们分别来验证一下.

  • 尝试写入(write)一个正在被执行的文件:

    # TERMINAL 1
    ➜ lane@vbox#2 ~ cat a.c        
    #include <unistd.h>
    
    int main() {
      sleep(60);
    }
    
    ➜ lane@vbox#2 ~ gcc a.c
    ➜ lane@vbox#2 ~ ./a.out 
    
    ##########################################
    ##########################################
    
    # TERMINAL 2
    # 此时可观察到 FD 是 txt, 说明该文件正在被执行中
    ➜ lane@vbox#2 ~ lsof a.out 
    COMMAND  PID USER  FD   TYPE DEVICE SIZE/OFF    NODE NAME
    a.out   2692 lane txt    REG  253,0     8480 9231359 a.out
    
    # 尝试使用写模式打开 a.out, 此时会报错
    ➜ lane@vbox#2 ~ python    
    Python 2.7.5 (default, Nov 16 2020, 22:23:17) 
    [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> open("a.out", "w")
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    IOError: [Errno 26] Text file busy: 'a.out'
    >>> 
    
  • 尝试执行(execute)一个正在被写入的文件.

    # 使用 FD 3 以写方式创建一个文件 example
    ➜ lane@vbox#2 ~ exec 3> example
    
    # 查看状态可见 FD 是 3, 且为 write 方式
    ➜ lane@vbox#2 ~ lsof example 
    COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
    zsh     1479 lane    3w   REG  253,0        0 8415983 example
    
    # 执行该文件会报错
    ➜ lane@vbox#2 ~ chmod u+x example 
    ➜ lane@vbox#2 ~ ./example  
    zsh: text file busy: ./example
    
    # sh example 并不会报错, 因为此时被执行的是 sh, 而不是 example
    ➜ lane@vbox#2 ~ sh example
    ➜ lane@vbox#2 ~ 
    

至此, 两种情况全部验证成功.

Comments
Write a Comment