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


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한 다음 새로 지어 이동 (링크 해제했다 이름 바꾸기 문제가 아니었다) rmk1에 rmk.

나는 현대 시스템에서 오류를 꽤 오랫동안 보지 못했습니다 ...하지만 종종 프로그램을 스스로 재구성하는 것은 아닙니다.


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.