파일이 닫 혔을 때만 이동


10

외부 프로세스에서 만든 큰 파일을 닫 자마자 이동하고 싶습니다.

이 테스트 명령이 맞습니까?

if lsof "/file/name"
then
        # file is open, don't touch it!
else
        if [ 1 -eq $? ]
        then
                # file is closed
                mv /file/name /other/file/name
        else
                # lsof failed for some other reason
        fi
fi

편집 : 파일은 데이터 세트를 나타내며 다른 프로그램이 작동 할 수 있도록 이동이 완료 될 때까지 기다려야합니다. 그래서 외부 프로세스가 파일로 완료되었는지 알아야합니다.


3
참고 : 파일이 열리면 프로세스는 파일 디스크립터와 inode 데이터를 사용하여 파일을 조작합니다. 경로를 변경하면 (예 : 파일 이동) 프로세스에 너무 많은 문제가 발생하지 않습니다.
John WH Smith

2
외부 프로세스를 제어 할 수 있습니까? 외부 프로세스가 임시 파일을 작성하고 파일 쓰기가 끝나면 파일 이름을 바꿀 수 있습니까?
Jenny D

@JennyD 나는 약간의 조사를했고 그것은 사실로 밝혀졌습니다. 나는 필요하지 않습니다 lsof단지 파일 확장자가 아닌지 확인하기 위해 필요한 모든 I에서 .tmp. 그것은 사소한 일입니다. 그러나 나는에 대해 조금 배운 이후로 내 질문을 기뻐 lsof하고 inotify물건.
Peter Kovac

@PeterKovac 나는 답변을 읽음으로써 그들에 대해 더 많이 배웠습니다.
Jenny D

@JohnWHSmith-동일한 파일 시스템 내에서 파일을 이동하면 작성기가 파일을 쓰기 전에 파일을 새 파일 시스템으로 이동하면 일부 데이터가 손실됩니다.
Johnny

답변:


11

로부터 lsofman 페이지

Lsof는 명령 이름, 파일 이름, 인터넷 주소 또는 파일, 로그인 이름, NFS 파일, PID, PGID 또는 UID를 나열하도록 요청하지 않은 등 오류가 발견되면 1을 반환합니다. -V 옵션이 지정되면 lsof는 나열하지 못한 검색 항목을 나타냅니다.

따라서 lsof failed for some other reason절이 실행되지 않을 것을 제안합니다 .

외부 프로세스가 여전히 열려있는 동안 파일을 이동하려고 했습니까? 대상 디렉토리가 동일한 파일 시스템에있는 경우, 기본 inode가 동일하게 유지되므로 세 번째 프로세스에서 원래 경로로 디렉토리에 액세스 할 필요가 없으면이를 수행하는 데 아무런 문제가 없습니다. 그렇지 않으면 mv어쨌든 실패 할 것이라고 생각 합니다.

파일에서 외부 프로세스가 완료 될 때까지 기다려야하는 경우 반복적으로 폴링하는 대신 차단하는 명령을 사용하는 것이 좋습니다. Linux에서는이를 사용할 수 있습니다 inotifywait. 예 :

 inotifywait -e close_write /path/to/file

lsof(이동성을 위해) 사용해야 할 경우 다음과 같이 시도 할 수 있습니다.

until err_str=$(lsof /path/to/file 2>&1 >/dev/null); do
  if [ -n "$err_str" ]; then
    # lsof printed an error string, file may or may not be open
    echo "lsof: $err_str" >&2

    # tricky to decide what to do here, you may want to retry a number of times,
    # but for this example just break
    break
  fi

  # lsof returned 1 but didn't print an error string, assume the file is open
  sleep 1
done

if [ -z "$err_str" ]; then
  # file has been closed, move it
  mv /path/to/file /destination/path
fi

최신 정보

아래 @JohnWHSmith에서 언급했듯이 , 가장 안전한 디자인은 lsof둘 이상의 프로세스가 쓰기 위해 파일을 열 수 있기 때문에 항상 위와 같은 루프를 사용합니다 (예를 들어 읽기로 파일을 여는 색인 작성 데몬이 잘못 될 수 있음) 실제로 읽기 전용이어야 할 경우 / write 플래그). inotifywait그래도 수면 대신 사용할 수 있습니다 inotifywait -e close /path/to/file. 수면 라인을로 교체하십시오 .


고마워, 나는 몰랐다 inotify. 불행히도, 그것은 내 상자에 설치되어 있지 않지만 어딘가에서 패키지를 찾을 것이라고 확신합니다. 파일을 닫아야하는 이유는 편집 한 내용을 참조하십시오. 파일은 데이터 세트이므로 처리하기 전에 완료해야합니다.
Peter Kovac

1
또 다른 참고 사항 : inotifywait스크립트가 두 번 "폴링"하지 못하게하는 동안 OP는 여전히 lsof루프 를 체크인해야 합니다. 파일을 두 번 열면 한 번 닫으면 inotify이벤트 가 트리거 될 수 있습니다. 조작 (예 : 마지막 코드 스 니펫에서 sleep통화가로 대체 될 수 있음 inotifywait).
John WH Smith

@John a close_write는 한 번에 하나의 프로세스 만 쓰기 위해 파일을 열 수 있으므로 괜찮습니다. 다른 하나가 닫힌 후에 바로 열지 않는다고 가정하지만 lsof폴링 과 동일한 문제가 있습니다 .
Graeme

1
@Graeme OP의 경우 의도적으로 이것은 사실 일 수 있지만 커널은 파일을 쓰기 위해 두 번 열 수 있습니다 (이 경우 CLOSE_WRITE두 번 트리거 됨).
John WH Smith

@John, 업데이트되었습니다.
Graeme

4

대안적인 접근법으로서, 이것은 파이프 의 완벽한 사례입니다. 두 번째 프로세스는 전체 프로세스가 완료되기를 기다리지 않고 첫 번째 프로세스의 출력을 가능한 빨리 처리합니다.

process1 input_file.dat | process2 > output_file.dat

장점 :

  • 일반적으로 훨씬 빠릅니다.
    • 디스크에 쓰고 읽을 필요가 없습니다 (램 디스크를 사용하는 경우 피할 수 있습니다).
    • 기계 자원을보다 완전하게 사용해야합니다.
  • 완료 후 제거 할 중간 파일이 없습니다.
  • OP에서와 같이 복잡한 잠금이 필요하지 않습니다.

파이프를 직접 만들 방법이 없지만 GNU coreutils가있는 경우 다음을 사용할 수 있습니다.

tail -F -n +0 input_file.dat | process2 > output_file.dat

첫 번째 프로세스가 파일 쓰기를 통해 얼마나 멀리 진행 되더라도 (아직 시작되지 않았거나 이미 완료된 경우에도) 시작부터 입력 파일을 읽기 시작 합니다.


예, "분명한"솔루션입니다. 불행히도, 데이터 생성 프로세스가 제어 할 수 없습니다 (다른 사용자가 실행).
Peter Kovac

@PeterKovac 관련이 없습니다 : cat input_file.dat | process2 output_file.dat
MariusMatutiae

@MariusMatutiae하지만 catprocess2이전에 완료 할 수 process1완료됩니다. 그들은 차단하지 않습니다.
cpugeniusmv 2016
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.