อะไรทำให้เกิดข้อความ "ไฟล์ข้อความไม่ว่าง" ใน Unix


145

การดำเนินการใดทำให้เกิดข้อผิดพลาด "ไฟล์ข้อความไม่ว่าง" ฉันไม่สามารถบอกได้อย่างแน่ชัด

ฉันคิดว่ามันเกี่ยวข้องกับการที่ฉันสร้างสคริปต์ python ชั่วคราว (โดยใช้ tempfile) และใช้ execl จากมัน แต่ฉันคิดว่า execl เปลี่ยนไฟล์ที่กำลังเรียกใช้

คำตอบ:


138

ข้อผิดพลาดนี้หมายถึงกระบวนการอื่น ๆ หรือผู้ใช้กำลังเข้าถึงไฟล์ของคุณ ใช้lsofตรวจสอบกระบวนการอื่นที่ใช้อยู่ คุณสามารถใช้killคำสั่งเพื่อฆ่ามันได้หากจำเป็น


118
Text file busyผิดพลาดในที่เฉพาะเจาะจงเกี่ยวกับการพยายามที่จะปรับเปลี่ยนปฏิบัติการในขณะที่มีการดำเนินการ "ข้อความ" ในที่นี้หมายถึงความจริงที่ว่าไฟล์ที่กำลังแก้ไขคือส่วนข้อความสำหรับโปรแกรมที่กำลังทำงานอยู่ นี่เป็นกรณีพิเศษมากไม่ใช่กรณีทั่วไปที่ดูเหมือนว่าคำตอบของคุณจะแนะนำ ถึงกระนั้นคำตอบของคุณก็ไม่ถูกต้องทั้งหมด
ArjunShankar

5
คำตอบพร้อมความคิดเห็นดูเหมือนจะสมบูรณ์
Penz

OP ถามว่าการดำเนินการใดทำให้เกิดข้อผิดพลาดไม่ใช่เพื่อการอธิบายความหมายของข้อผิดพลาด
WonderWorker

ฉันคิดว่าความจริงที่ว่า unix ถือว่าไฟล์เป็น "ไฟล์ข้อความ" นั้นเป็น ilogical ในกรณีของฉันมันเป็นไฟล์ไบนารีที่แจ้งข้อผิดพลาดนี้
Felipe Valdes

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จากนั้นย้ายไฟล์เก่าrmkไปที่rmk2(เปลี่ยนชื่อไม่ใช่ปัญหายกเลิกการลิงก์) จากนั้นย้ายไฟล์ที่สร้างขึ้นใหม่rmk1ไปยังrmkไฟล์.

ฉันไม่เห็นข้อผิดพลาดในระบบที่ทันสมัยมาระยะหนึ่งแล้ว ... แต่ฉันก็ไม่ใช่ทั้งหมดที่มักจะสร้างโปรแกรมขึ้นมาใหม่


3
นี่เป็น reproducer 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ซุปเปอร์อย่างรวดเร็ว: สร้างข้อความแสดงข้อผิดพลาด "cp: ไม่สามารถสร้างไฟล์ปกติ" a.out ": ไฟล์ข้อความไม่ว่าง" บน Fedora ใหม่ของฉัน
ArjunShankar

@ArjunShankar นี่คือการทำสำเนา C บนลินุกซ์สมัยใหม่ที่มีการเรียกระบบ "โดยตรง": stackoverflow.com/questions/16764946/… GCC สามารถเขียนทับไฟล์ปฏิบัติการที่รันอยู่ในปัจจุบันได้เท่านั้นเพราะหากเป็นครั้งแรกunlinkโดยค่าเริ่มต้น
Ciro Santilli 郝海东冠状病六四事件法轮功

18

สิ่งนี้เกิดขึ้นเมื่อคุณพยายามและเขียนไปยังไฟล์ที่กำลังดำเนินการโดยเคอร์เนลหรือเรียกใช้ไฟล์ที่กำลังเปิดอยู่สำหรับการเขียน

ที่มา: http://wiki.wlug.org.nz/ETXTBSY


9

ตัวอย่างการสร้าง C POSIX ที่รันได้น้อยที่สุด

ฉันขอแนะนำให้ทำความเข้าใจกับ API พื้นฐานเพื่อดูว่าเกิดอะไรขึ้น

นอนหลับ c

#define _XOPEN_SOURCE 700
#include <unistd.h>

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

ไม่ว่าง c

#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 kernel 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

ที่ไม่ก่อให้เกิดข้อผิดพลาดแม้สองสายจะเขียนถึงgccsleep.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มันก็จะพยายามเขียนไปยังไอโหนดที่ได้รับการป้องกันเช่นเดียวกับปฏิบัติการที่รันอยู่

POSIX 7 open()

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

[ETXTBSY]

ไฟล์นี้เป็นไฟล์โพรซีเดอร์บริสุทธิ์ (ข้อความที่แบ่งใช้) ที่กำลังดำเนินการและ oflag คือ O_WRONLY หรือ O_RDWR

ชาย 2 เปิด

ETXTBSY

ชื่อพา ธ หมายถึงอิมเมจที่เรียกใช้งานได้ซึ่งกำลังดำเนินการอยู่และร้องขอการเข้าถึงการเขียน

ที่มา glibc

grep อย่างรวดเร็วบน 2.30 ช่วยให้:

sysdeps/gnu/errlist.c:299:    [ERR_REMAP (ETXTBSY)] = N_("Text file busy"),
sysdeps/mach/hurd/bits/errno.h:62:  ETXTBSY                        = 0x4000001a,        /* Text file busy */

และตีด้วยตนเองในmanual/errno.texi:

@deftypevr Macro int ETXTBSY
@standards{BSD, errno.h}
@errno{ETXTBSY, 26, Text file busy}
An attempt to execute a file that is currently open for writing, or
write to a file that is currently being executed.  Often using a
debugger to run a program is considered having it open for writing and
will cause this error.  (The name stands for ``text file busy''.)  This
is not an error on @gnuhurdsystems{}; the text is copied as necessary.
@end deftypevr

2
เหตุผลสำหรับกรณียกเลิกการเชื่อมโยงคือไฟล์ไม่สามารถเข้าถึงได้จากไดเร็กทอรีนั้นอีกต่อไป แต่ไอโหนดยังคงอยู่ที่นั่นโดยมีการอ้างอิง> 0 หากคุณใช้ชื่อซ้ำจะเป็นไฟล์ใหม่ในไอโหนดใหม่ - ในขณะที่ถ้า คุณไม่ได้ยกเลิกการเชื่อมโยงก่อน แต่คุณกำลังพยายามเขียนถึงไอโหนดที่ได้รับการป้องกัน
Penz

@Penz obrigado สำหรับความคิดเห็น Leandro unlinkฉันยังสงสัยว่าทำไมตรงกันข้ามไม่ได้ให้ข้อผิดพลาดถ้าคุณพยายามที่จะเขียนได้โดยไม่ต้อง Linux เคยอ่านไฟล์มากกว่าหนึ่งครั้งหลังจากการexecโทรครั้งแรกหรือไม่?
Ciro Santilli 郝海东冠状病六四事件法轮功

สิ่งที่สร้าง ETXTBSY คือการป้องกันไอโหนด โดยไม่ต้องยกเลิกการเชื่อมโยงการเขียนใด ๆ จะไปที่ไอโหนดที่ได้รับการป้องกันโดยการเรียกใช้ไฟล์ เมื่อยกเลิกการลิงก์คุณจะได้รับไอโหนดใหม่ที่ไม่ได้รับการป้องกัน (ไม่แน่ใจว่าคำว่า "ป้องกัน" เป็นคำที่นี่ แต่เป็นแนวคิด)
Penz

5

ในกรณีของฉันฉันพยายามเรียกใช้ไฟล์เชลล์ (ที่มีนามสกุล. sh) ในสภาพแวดล้อม csh และฉันได้รับข้อความแสดงข้อผิดพลาดนั้น

แค่วิ่งไปพร้อมกับทุบตีมันได้ผลสำหรับฉัน ตัวอย่างเช่น

bash file.sh


1
มันมี#!/bin/bashส่วนหัวหรือไม่?
Penz

มีส่วนหัวต่อไปนี้ #! / bin / sh
Rafayel Paremuzyan

คุณอาจต้องการลองใช้#!/usr/bin/cshหรือเทียบเท่า
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

ยังคงเป็นคำแนะนำที่ดีมากสำหรับผู้ที่ประสบปัญหานี้เมื่อสร้างภาพนักเทียบท่า
Maciej Gol

2

คุณอาจพบว่าสิ่งนี้พบได้บ่อยในการแชร์เครือข่าย CIFS / SMB Windows ไม่อนุญาตให้เขียนไฟล์เมื่อมีไฟล์อื่นเปิดอยู่และแม้ว่าบริการจะไม่ใช่ Windows (อาจเป็นผลิตภัณฑ์ NAS อื่น ๆ ) แต่ก็มีแนวโน้มที่จะสร้างพฤติกรรมเดียวกัน อาจเป็นไปได้ว่าอาจเป็นการแสดงให้เห็นถึงปัญหา NAS พื้นฐานบางอย่างที่เกี่ยวข้องกับการล็อก / การจำลองแบบคลุมเครือ


2

หากคุณกำลังเรียกใช้. sh จากการเชื่อมต่อ ssh ด้วยเครื่องมือเช่น MobaXTerm และหากเครื่องมือดังกล่าวมียูทิลิตี้บันทึกอัตโนมัติเพื่อแก้ไขไฟล์ระยะไกลจากเครื่องภายในระบบจะล็อกไฟล์

การปิดและเปิดเซสชัน SSH ใหม่จะช่วยแก้ปัญหาได้


2

ไม่ทราบสาเหตุ แต่ฉันสามารถมีส่วนร่วมในการแก้ไขปัญหาที่ง่ายและรวดเร็ว

ฉันเพิ่งพบความแปลกประหลาดนี้ใน CentOS 6 หลังจากcat > shScript.sh(วาง^Z) จากนั้นแก้ไขไฟล์ใน KWrite ผิดปกติไม่มีอินสแตนซ์ ( ps -ef) ที่มองเห็นได้ของการเรียกใช้สคริปต์

การแก้ไขปัญหาอย่างรวดเร็วของฉันเป็นเพียงแค่cp shScript.sh shScript2.shตอนนั้นฉันก็สามารถดำเนินการshScript2.shได้ จากนั้นฉันก็ลบทั้งสองอย่าง เสร็จแล้ว!


1
ปัญหาของคุณเพราะคุณถูกระงับcatกระบวนการ ใช้ครั้งต่อไป ^ D ไม่ใช่ ^ Z
Vladimir Panteleev

Vladimir ค่อนข้างถูกต้อง ขอบคุณ! นั่นคือสิ่งที่ฉันได้ทำในพรอมต์ DOS / CMD habbits เก่า ... ยังไม่เกิดขึ้นตั้งแต่ :)
ScottWelker

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

ฉันเจอสิ่งนี้ใน PHP เมื่อใช้fopen()กับไฟล์แล้วลองunlink()ใช้ก่อนใช้fclose()มัน

ไม่ดี:

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

ดี:

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

บน windows ฉันเดา? บน linux ระบบมักจะอนุญาตให้เราลบไฟล์ที่เปิดอยู่ - การอ้างอิงในไดเร็กทอรีจะถูกตัดออก แต่ข้อมูล (inode) จะถูกเฟรดก็ต่อเมื่อจำนวนการอ้างอิงถึง 0 เท่านั้น
Penz

ไม่นี่คือใน Centos
dtbarne

ทดสอบบน Linux 4.7.10 พร้อมระบบไฟล์ ext4 และไม่เกิดข้อผิดพลาดใด ๆ ทำงานตามที่ Penz กล่าวไว้ ลบไฟล์เรียบร้อยแล้ว บางที 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.