유닉스에서 "텍스트 파일 사용중"메시지를 생성하는 것은 무엇입니까?


137

"텍스트 파일 사용 중"오류가 발생하는 작업은 무엇입니까? 정확히 말할 수 없습니다.

임시 파이썬 스크립트 (tempfile 사용)를 만들고 execl을 사용한다는 사실과 관련이 있다고 생각하지만 execl은 실행중인 파일을 변경한다고 생각합니다.

답변:


130

이 오류는 다른 프로세스 나 사용자가 파일에 액세스하고 있음을 의미합니다. 사용하여 lsof다른 프로세스를 사용하고있는 것을 확인 할 수 있습니다. kill필요한 경우 명령을 사용하여 명령을 종료 할 수 있습니다 .


115
특히 Text file busy오류는 실행 파일이 실행되는 동안 수정하려고합니다. 여기서 "텍스트"는 수정중인 파일이 실행중인 프로그램 의 텍스트 세그먼트 라는 사실을 나타냅니다 . 이것은 매우 특별한 경우이며 귀하의 답변이 제안하는 일반적인 것은 아닙니다. 그럼에도 불구하고 귀하의 답변이 완전히 틀린 것은 아닙니다.
ArjunShankar

4
의견이있는 답은 완전한 것 같습니다.
Penz

OP는 오류의 의미에 대한 설명이 아니라 오류를 생성하는 작업을 요청했습니다.
WonderWorker

유닉스가 파일을 "텍스트 파일"이라고 가정한다는 사실은 비논리적이라고 생각합니다. 제 경우에는이 오류가 발생한 이진 파일이었습니다.
Felipe Valdes

1
@FelipeValdes 이름은 반세기 전의 용어에서 역사적입니다. 예를 들어, 멀티 플렉스에서 프로그램의 텍스트 세그먼트는 링크 세그먼트와 다르며 심지어 초기 사람들도 이진 텍스트에 대해 이야기했습니다. stackoverflow.com/a/1282540/833300
jma

30

그 메시지를 본 지 오래되었지만, System V R3에서 널리 사용되거나 수십 년 전에 널리 사용되었습니다. 당시에는 실행중인 프로그램 실행 파일을 변경할 수 없었습니다.

예를 들어, 나는 make이라는 이름 의 workalike 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한 다음 새로 지어 이동 (링크 해제했다 이름 바꾸기 문제가 아니었다) 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

3
물론이 답변은 정확하며 +1을 얻습니다. "오래되었습니다"면책 조항을 제거 할 수 있습니다.
ArjunShankar

@ArjunShankar는 "직접"시스템 호출을 통해 최신 Linux에서 C를 재생산 한 것입니다 : stackoverflow.com/questions/16764946/… GCC는 요즘 실행중인 실행 파일 만 덮어 쓸 수 있습니다 unlink.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功


6

최소 실행 가능 C POSIX 재생 예

무슨 일이 일어나고 있는지 더 잘 보려면 기본 API를 이해하는 것이 좋습니다.

sleep.c

#define _XOPEN_SOURCE 700
#include <unistd.h>

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

busy.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.outassert를 전달하고 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는 파일을 다시 쓰고 쓸 때 새 inode를 만들고 실행중인 실행 파일에 대한 임시 매달린 inode를 유지하기 때문입니다.

그러나 당신이 write없는 경우 unlink실행중인 실행 파일과 동일한 보호 된 inode에 쓰려고합니다.

POSIX 7 open()

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

[ETXTBSY]

파일은 실행중인 순수 프로 시저 (공유 텍스트) 파일이며 oflag는 O_WRONLY 또는 O_RDWR입니다.

남자 2 오픈

ETXTBSY

pathname은 현재 실행 중이고 쓰기 액세스가 요청 된 실행 가능 이미지를 나타냅니다.


1
연결 해제 사례의 이론적 근거는 파일이 해당 디렉토리에서 더 이상 액세스 할 수 없지만 inode가 여전히 refcount> 0으로 존재한다는 것입니다. 이름을 다시 사용하면 새 inode의 새 파일이됩니다. 먼저 연결을 해제하지 않고 실제로 보호 된 inode에 쓰려고합니다.
Penz

댓글에 대한 @Penz obrigado, Leandro. 또한 반대로 작성하지 않으면 왜 오류가 발생하는지 궁금합니다 unlink. 리눅스는 첫 번째 exec호출 후 파일을 두 번 이상 읽었 습니까?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

ETXTBSY를 생성하는 것은 inode 보호입니다. 연결을 해제하지 않으면 모든 쓰기가 파일 실행으로 보호되는 inode로 이동합니다. 연결을 해제하면 보호되지 않은 새로운 inode를 얻게됩니다. (여기서 "보호 된"이라는 용어는 확실하지 않지만 그 아이디어입니다)
Penz

5

내 경우에는 csh 환경에서 셸 파일 (확장명이 .sh 인)을 실행하려고했지만 오류 메시지가 나타납니다.

bash로 실행하면 나를 위해 일했습니다. 예를 들어

bash file.sh


1
그것은 있었나요 #!/bin/bash헤더를?
Penz

그것은 다음과 같은 헤더를 가지고 있습니다 #! / bin / sh
Rafayel Paremuzyan

당신은 사용 #!/usr/bin/csh하거나 동등한 것을 시도 할 수 있습니다 .
Penz

3

phpredisLinux 박스 에서 빌드 를 시도하는 경우 파일 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

원인을 모르지만 신속하고 쉬운 해결 방법을 제공 할 수 있습니다.

방금 "cat> shScript.sh"(붙여 넣기, ^ Z) 후 CentOS 6에서이 이상한 점을 경험 한 다음 KWrite에서 파일을 편집했습니다. 이상하게도 스크립트 실행에 대한 식별 가능한 인스턴스 (ps -ef)가 없었습니다.

내 빠른 해결 방법은 단순히 "cp shScript.sh shScript2.sh"에 대한 것이었고 shScript2.sh를 실행할 수있었습니다. 그런 다음 둘 다 삭제했습니다. 끝난!


당신이 있기 때문에 귀하의 문제였다 중단cat 과정을. 다음에는 ^ Z가 아니라 ^ D를 사용하십시오.
Vladimir Panteleev 5

바로 블라디미르. 감사! 그것이 DOS / CMD 프롬프트에서 한 것입니다. 오래된 habbits ... 이후로 일어나지 않았습니다 :)
ScottWelker

2

CIFS / SMB 네트워크 공유에서 더 일반적 일 수 있습니다. Windows는 다른 파일을 열어 놓았을 때 파일을 쓸 수 없으며 서비스가 Windows가 아니더라도 (다른 NAS 제품 일 수 있음) 동일한 동작을 재현 할 수 있습니다. 잠재적으로 잠금 / 복제와 모호한 일부 기본 NAS 문제가 나타날 수도 있습니다.


2

MobaXTerm과 같은 도구를 사용하여 ssh 연결에서 .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');

창문에서 나는 추측? 리눅스에서 시스템은 일반적으로 열려있는 파일을 삭제할 수있게합니다. 디렉토리의 참조는 제거되지만 참조 수는 0에 도달 할 때만 데이터 (노이드)가 열성입니다.
Penz

아니요, Centos에있었습니다.
dtbarne

ext4 파일 시스템으로 Linux 4.7.10에서 테스트했으며 Penz가 언급 한대로 오류가 발생하지 않았습니다. 파일이 성공적으로 삭제되었습니다. 아마도 dtbarne이 특별한 파일 시스템을 사용하고있을 것입니다.
k3a

이것을 vagrant에서 실행 중입니다-공유 폴더 때문일 수 있습니다.
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

코드를 답변으로 게시하지 말고 코드의 기능과 질문의 문제를 해결하는 방법에 대한 설명도 제공하십시오. 설명이 포함 된 답변은 일반적으로 도움이되고 품질이 우수하며 투표를 유도 할 가능성이 높습니다.
마크 Rotteveel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.