Điều gì tạo ra tập tin văn bản trên nền tảng tin nhắn bận rộn trong Unix?


136

Hoạt động nào tạo ra lỗi "tập tin văn bản bận"? Tôi không thể nói chính xác.

Tôi nghĩ nó có liên quan đến thực tế là tôi đang tạo một tập lệnh python tạm thời (sử dụng tempfile) và sử dụng execl từ nó, nhưng tôi nghĩ rằng execl thay đổi tập tin đang chạy.

Câu trả lời:


130

Lỗi này có nghĩa là một số quá trình hoặc người dùng khác đang truy cập tệp của bạn. Sử dụng lsofđể kiểm tra những quy trình khác đang sử dụng nó. Bạn có thể sử dụng killlệnh để giết nó nếu cần.


115
Các Text file busylỗi trong cụ thể là về việc cố gắng để thay đổi một thực thi trong khi nó đang thực hiện. "Văn bản" ở đây đề cập đến thực tế rằng tệp đang được sửa đổi là phân đoạn văn bản cho một chương trình đang chạy. Đây là một trường hợp rất đặc biệt, và không phải là trường hợp chung chung mà câu trả lời của bạn dường như gợi ý. Mặc dù vậy, câu trả lời của bạn không hoàn toàn không chính xác.
ArjunShankar

4
Câu trả lời với nhận xét có vẻ đầy đủ.
Penz

OP đã hỏi thao tác nào tạo ra lỗi, không phải để giải thích ý nghĩa của lỗi.
WonderWorker

Tôi nghĩ rằng thực tế rằng unix giả định các tệp là "tệp văn bản" là không hợp lệ, trong trường hợp của tôi, đó là một tệp nhị phân đã gây ra lỗi này.
Felipe Valdes

1
@FelipeValdes Cái tên này mang tính lịch sử từ thuật ngữ của nửa thế kỷ trước. Ví dụ, trong đa văn bản, phân đoạn văn bản của một chương trình khác với phân đoạn liên kết và thậm chí những người trước đó đã nói về văn bản nhị phân. stackoverflow.com/a/1282540/833300
jma

30

Lâu lâu tôi mới thấy tin nhắn đó, nhưng nó đã từng phổ biến trong System V R3 hoặc một vài năm trước đây. Trước đó, điều đó có nghĩa là bạn không thể thay đổi chương trình thực thi trong khi nó đang chạy.

Ví dụ, tôi đang xây dựng một chiếc xe makeđược gọi là công việc rmk, và sau một thời gian nó tự duy trì. Tôi sẽ chạy phiên bản phát triển và để nó xây dựng một phiên bản mới. Để làm cho nó hoạt động, cần phải sử dụng cách giải quyết:

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

Vì vậy, để tránh sự cố với 'tệp văn bản bận', bản dựng đã tạo một tệp mới rmk1, sau đó chuyển tệp cũ rmksang rmk2(đổi tên không thành vấn đề; hủy liên kết là), rồi chuyển tệp mới được xây dựng rmk1sangrmk .

Tôi đã không thấy lỗi trên một hệ thống hiện đại trong một thời gian dài ... nhưng tôi không thường xuyên có các chương trình tự xây dựng lại.


3
Đây là một trình tái tạo siêu nhanh : 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. Đã tạo thông báo lỗi "cp: không thể tạo tệp thông thường 'a.out': Tệp văn bản bận" trên Fedora mới của tôi.
ArjunShankar

3
Tất nhiên, câu trả lời này là chính xác và được +1. Bạn có thể muốn xóa từ chối trách nhiệm "Đã được một lúc".
ArjunShankar

@ArjunShankar ở đây là bản sao chép C trên Linux hiện đại với các cuộc gọi hệ thống "trực tiếp": stackoverflow.com/questions/16764946/, GCC chỉ có thể ghi đè lên các tệp thực thi hiện nay bởi vì trước tiên, unlinkmặc định sẽ thực hiện theo mặc định.
Ciro Santilli 郝海东 冠状 病 事件

14

Điều này xảy ra khi bạn thử và ghi vào một tệp hiện đang được thực thi bởi kernel hoặc thực thi một tệp hiện đang mở để ghi.

Nguồn: http://wiki.wlug.org.nz/ETXTBSY


6

Ví dụ sinh sản C POSIX tối thiểu

Tôi khuyên bạn nên hiểu API cơ bản để thấy rõ hơn những gì đang diễn ra.

ngủ

#define _XOPEN_SOURCE 700
#include <unistd.h>

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

bận

#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);
}

Biên dịch và chạy:

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

busy.outvượt qua các khẳng định và perrorđầu ra:

Text file busy

vì vậy chúng tôi suy luận rằng thông điệp được mã hóa cứng trong chính glibc.

Cách khác:

echo asdf > sleep.out

làm cho đầu ra Bash:

-bash: sleep.out: Text file busy

Đối với một ứng dụng phức tạp hơn, bạn cũng có thể quan sát nó với strace:

strace ./busy.out

trong đó có:

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

Đã thử nghiệm trên Ubuntu 18.04, nhân Linux 4.15.0.

Lỗi không xảy ra nếu bạn unlinklần đầu tiên

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);
}

Sau đó biên dịch và chạy tương tự như trên, và những khẳng định đó vượt qua.

Điều này giải thích tại sao nó hoạt động cho các chương trình nhất định nhưng không phải là chương trình khác. Ví dụ: nếu bạn làm:

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

điều đó không tạo ra lỗi, mặc dù gcccuộc gọi thứ hai đang ghisleep.out .

Một cách nhanh chóng stracecho thấy GCC bỏ liên kết đầu tiên trước khi viết:

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

chứa đựng:

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

Lý do nó không thất bại là khi bạn unlink và viết lại tệp, nó tạo ra một nút mới và giữ một nút tạm thời lơ lửng cho tệp thực thi đang chạy.

Nhưng nếu bạn writekhông có unlink, thì nó sẽ cố gắng ghi vào cùng một nút được bảo vệ như đang chạy.

POSIX 7 open()

http://pub.opengroup.org/onlinepub/9699919799/fifts/open.html

[ETXTBSY]

Tệp này là một tệp thủ tục thuần túy (văn bản chia sẻ) đang được thực thi và oflag là O_WRONLY hoặc O_RDWR.

người đàn ông 2 mở

ETXTBSY

tên đường dẫn đề cập đến một hình ảnh thực thi hiện đang được thực thi và yêu cầu truy cập ghi.


1
Lý do cho trường hợp hủy liên kết là tệp không còn truy cập được từ thư mục đó, nhưng inode vẫn ở đó với số lần truy cập> 0. Nếu bạn sử dụng lại tên, thì đó là một tệp mới trong một nút mới - trong khi đó trước tiên bạn không hủy liên kết, bạn thực sự đang cố gắng ghi vào nút được bảo vệ.
Penz

@Penz obrigado cho bình luận, Leandro. Tôi cũng tự hỏi tại sao, ngược lại, nó có lỗi hay không nếu bạn cố viết mà không có unlink. Linux có bao giờ đọc tệp nhiều hơn một lần sau execcuộc gọi đầu tiên không?
Ciro Santilli 郝海东 冠状 病 事件

Điều tạo ra ETXTBSY là bảo vệ inode. Nếu không hủy liên kết, mọi ghi sẽ chuyển đến inode được bảo vệ bởi thực thi tệp; với unlink, bạn nhận được một nút mới không được bảo vệ. (không chắc chắn "được bảo vệ" là thuật ngữ ở đây, nhưng đó là ý tưởng)
Penz

5

Trong trường hợp của tôi, tôi đã cố gắng thực thi một tệp shell (có phần mở rộng .sh) trong môi trường csh và tôi đã nhận được thông báo lỗi đó.

chỉ chạy với bash nó làm việc cho tôi. Ví dụ

bash file.sh


1
Nó có một #!/bin/bashtiêu đề?
Penz

Nó có tiêu đề #! / Bin / sh sau đây
Rafayel Paremuzyan

Bạn có thể muốn thử sử dụng #!/usr/bin/cshhoặc tương đương.
Penz

3

Nếu cố gắng xây dựng phpredistrên một hộp Linux, bạn có thể cần cho nó thời gian để hoàn thành sửa đổi các quyền của tệp, bằng một sleeplệnh, trước khi chạy tệp:

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

Tôi không nghĩ chmodsẽ trở lại trước khi quyền được thiết lập. Đó có thể là một vấn đề hệ thống tập tin.
Penz

Điều này xảy ra bên trong một hình ảnh Docker đang được xây dựng.
Stephane

1
Docker có nhiều trình điều khiển lưu trữ, tôi đoán không phải tất cả chúng đều hoàn hảo.
Penz

Tuy nhiên, đó là một gợi ý rất tốt cho những người gặp phải vấn đề này khi xây dựng hình ảnh docker.
Maciej Gol

2

Không biết nguyên nhân nhưng tôi có thể đóng góp một công việc nhanh chóng và dễ dàng.

Tôi vừa trải nghiệm sự kỳ lạ này trên CentOS 6 sau khi "cat> shScript.sh" (dán, ^ Z) sau đó chỉnh sửa tệp trong KWrite. Điều kỳ lạ là không có trường hợp rõ ràng (ps -ef) của việc thực thi tập lệnh.

Công việc nhanh chóng của tôi chỉ đơn giản là "cp shScript.sh shScript2.sh" sau đó tôi có thể thực thi shScript2.sh. Sau đó tôi xóa cả hai. Làm xong!


Vấn đề của bạn là do bạn bị đình chỉ các catquá trình. Lần sau sử dụng ^ D, không ^ Z.
Vladimir Panteleev

Khá đúng Vladimir. Cảm ơn! Đó là những gì tôi đã làm trong dấu nhắc DOS / CMD. Những
thói quen

2

Bạn có thể thấy điều này phổ biến hơn trên các chia sẻ mạng CIFS / SMB. Windows không cho phép ghi tệp khi có tệp khác mở tệp đó và ngay cả khi dịch vụ không phải là Windows (có thể là một số sản phẩm NAS khác), nó có thể sẽ tái tạo hành vi tương tự. Có khả năng, nó cũng có thể là một biểu hiện của một số vấn đề NAS tiềm ẩn liên quan đến việc khóa / sao chép.


2

Nếu bạn đang chạy .sh từ kết nối ssh với một công cụ như MobaXTerm và nếu công cụ đó có tiện ích tự động lưu để chỉnh sửa tệp từ xa từ máy cục bộ, điều đó sẽ khóa tệp.

Đóng và mở lại phiên SSH sẽ giải quyết nó.


1

Một trong những kinh nghiệm của tôi:

Tôi luôn thay đổi phím tắt mặc định của Chrome thông qua kỹ thuật đảo ngược. Sau khi sửa đổi, tôi quên đóng Chrome và chạy như sau:

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

Sử dụng strace, bạn có thể tìm thấy nhiều chi tiết hơn:

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

Tôi đã bắt gặp điều này trong PHP khi sử dụng fopen()trên một tệp và sau đó thử unlink()nó trước khi sử dụngfclose() nó.

Không tốt:

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

Tốt

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

Tôi đoán trên cửa sổ? Trên Linux hệ thống thường cho phép chúng ta xóa các tập tin mở - tài liệu tham khảo trong thư mục được loại bỏ, nhưng dữ liệu (inode) là fred chỉ khi số lượng tài liệu tham khảo đạt 0.
Penz

Không, đây là trên Centos.
dtbarne

Đã thử nghiệm nó trên Linux 4.7.10 với hệ thống tập tin ext4 và nó không tạo ra bất kỳ lỗi nào, hoạt động như đã đề cập. Xóa tập tin thành công. Có lẽ dtbarne đang sử dụng một số hệ thống tập tin đặc biệt.
k3a

Đã chạy cái này trên vagrant - có thể là do nó là một thư mục dùng chung.
dtbarne 17/03/2017

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

Vui lòng không chỉ đăng mã dưới dạng câu trả lời mà còn cung cấp giải thích về mã của bạn làm gì và cách giải quyết vấn đề của câu hỏi. Câu trả lời với một lời giải thích thường hữu ích hơn và có chất lượng tốt hơn, và có nhiều khả năng thu hút upvote.
Đánh dấu Rotteveel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.