Bash(리눅스)에서 filedescriptor가 가리키는 파일이 삭제되었는지 확인하고 싶습니다.
다 읽었어파일 설명자가 유효한지 테스트그리고파일 설명자가 유효한지 테스트(입력용). 그러나 이러한 답변은 약간 다른 질문에 도움이 되지 않습니다.
다음 테스트 케이스를 사용합니다.
# create file
echo hello > /tmp/test.txt
# open read-only fd
exec 3< /tmp/test.txt
# delete file
rm /tmp/test.txt
# special zero-timeout to check if data available for reading
if read -u 3 -t 0
then
echo "data available for reading"
else
echo "no data available"
fi
# close fd (clean up)
exec 3<&-
스크립트는 놀랍게도 "데이터를 읽을 수 있습니다"라고 말합니다. 그러나 파일이 더 이상 존재하지 않습니다. 따라서 일부 캐싱/버퍼링이 수행되어야 합니다. 어쩌면 다른 방법이 있을까요, 아니면 버퍼/캐싱을 피할까요?
또 다른 가능한 접근 방식은 ls -l /proc/$$/fd/3
다음과 같습니다 -> '/tmp/test.txt (deleted)'
. 그러나 저는 순수한 Bash 솔루션을 선호합니다(너무 많은 새 프로세스를 생성하지 않거나 표준 출력을 구문 분석하지 않음).
다른 경우에는 물론 [ -e /tmp/test.txt ]
수표를 사용할 수도 있습니다. 하지만 원본 파일이 삭제되었는지는 알아야 합니다.정확히 동일한 파일 이름을 가진 새 파일이 동시에 생성될 수 있습니다..
왜 누군가에게 이 특정 결과가 필요한지 궁금하신 분들을 위해(XY 문제), 이는 재활용된 PID와의 충돌을 방지하기 &
위해 추가 fd를 열어 상위 스크립트가 여전히 실행 중인지 여부를 하위 쉘에서 ( 사용하여) 안전하게 확인하는 데 사용할 수 있습니다./proc/$$/cmdline
답변1
파일 설명자가 파일 시스템의 모든 디렉터리에 남아 있는 링크가 없는 일반 파일을 참조하는지 테스트하려면 해당 파일에 대한 시스템 호출을 수행하고 반환된 구조의 fstat()
링크(필드) 수를 확인할 수 있습니다.st_nlink
that을 사용하면 내장 함수를 zsh
사용하여 stat
이 작업을 수행 할 수 있습니다.
zmodload zsh/stat
fd=3
if
stat -s -H st -f $fd && # can be fstat'ed (is an opened fd)
[[ $st[mode] = -* ]] && # is a regular file
((st[nlink] == 0)) # has no link on the filesystem
then
print fd $fd is open on a regular file that has no link in the filessystem
fi
bash
(GNU 쉘) 이에 상응하는 것은 없지만 GNU 시스템을 사용하고 있다면 아마도 GNU가 있을 것입니다. stat
이 경우 다음을 수행할 수 있습니다:
fd=3
if [ "$(LC_ALL=C stat -c %F:%h - <&"$fd")" = 'regular file:0' ]; then
printf '%s\n' "fd $fd is open on a regular file that has no link in the filessystem"
fi
zsh
OS 커널이 Linux인 경우 proc 파일 시스템이 마운트되어 있다고 가정하고 더 이식 가능한 접근 방식(커널이 없고 핵심 유틸리티가 GNU에서 제공되지 않는 경우 )은 다음을 사용 /proc
하는 것입니다 .ls
/proc/self/fd/$fd
if
LC_ALL=C TZ=UTC0 ls -nLd /proc/self/fd/0 <&"$fd" |
LC_ALL=C awk -v ret=1 '
NF {if ($1 ~ /^-/ && $2 == 0) ret=0; exit}
END {exit(ret)}'
then
printf '%s\n' "fd $fd is open on a regular file that has no link in the filessystem"
fi
이는 이전 솔루션처럼 fd를 0에 복사하므로 fd에 close-on-exec 플래그가 있어도 작동합니다(fd가 처음에 0이 아니라고 가정하지만 fd 0에는 일반적으로 close-on-exec가 없습니다). 깃발) 배너).
이 방법은 열린 fd가 /proc/<some-pid>/cmdline
실시간 프로세스를 참조하는지 확인하기 위해 Linux의 procfs 가짜 파일 시스템에서 작동하지 않습니다.
$ zsh -c 'zmodload zsh/stat; (sleep 1; stat -f0 +nlink; cat) < /proc/$$/cmdline &'
$ 1
cat: -: No such process
fstat().st_nlink
위의 명령이 1(파일에 여전히 디렉터리에 대한 링크가 있음을 의미)을 반환하는 반면 fd의 cat
s는 read()
오류를 반환하는 방법을 확인하세요 . 이는 일반적인 파일 시스템 의미가 아닙니다.
어떤 경우든 상위 프로세스가 아직 실행 중인지 확인하려면 이를 호출할 수 있으며, getppid()
상위 프로세스가 종료되면 1 또는 하위 하위 하위 리퍼의 pid를 반환합니다. 에서는 (모듈에서 ) zsh
를 사용할 수 있습니다 .$sysparams[ppid]
zsh/system
$ sh -c 'zsh -c '\''zmodload zsh/system
print $PPID $sysparams[ppid]
sleep 2; print $PPID $sysparams[ppid]
'\'' & sleep 1'
14585 14585
$ 14585 1
에서는 bash
를 사용할 수 있습니다 ps -o ppid= -p "$BASHPID"
.
또 다른 방법은 부모와 자식 사이에 파이프를 만들고 select
/ poll
(또는 read -t0
in bash
)을 사용하여 파이프가 아직 실행 중인지 확인하는 것입니다.
coproc
bash
대신 (최근에 추가된)을 사용하여 이 작업을 수행할 수 있습니다 &
.
background_with_pipe() {
coproc "$@" {PARENT_FD}<&0 <&3 3<&- >&4 4>&-
} 3<&0 4>&1
parent_gone() {
local ignore
read -t0 -u "$PARENT_FD" ignore
}
background_with_pipe eval '
parent_gone || echo parent still there
sleep 2
parent_gone && echo parent gone
'
sleep 1
exit
다음을 제공합니다.
$ bash ./that-script
parent still there
$ parent gone
구상한 접근 방식을 기반으로 Linux 커널이 procfs
컴퓨터에 설치되어 있다고 가정하면 /proc
다음을 수행할 수도 있습니다.
exec {PARENT_CANARY}< /proc/self/cmdline; PARENT_PID=$BASHPID
parent_gone() {
! [[ /proc/$PARENT_PID/cmdline -ef /proc/self/fd/$PARENT_CANARY ]]
}
(
parent_gone || echo parent still there
sleep 2
parent_gone && echo parent gone
) &
sleep 1
[[ file1 -ef file2 ]]
파일의 dev 및 inode 번호가 동일한지 확인 st_dev
하고 st_ino
반환하려면 이를 사용합니다 stat()
.
이것은 5.6.0에서 작동하는 것처럼 보이지만 위에서 본 것처럼 /proc
일반적인 파일 시스템 의미를 따르지 않으며 경합이 없거나(PID 및 inode 번호가 재사용되었을 수 있음) 사용할 수 있다고 보장할 수 없습니다. 향후 Linux 버전에서는.
답변2
원본 파일은 완전히 변경되지 않았습니다.
파일이 이름으로 열리면 프로세스에 의해 저장된 파일 설명자는 파일에 대한 링크로 간주됩니다. 시스템은 모든 링크가 제거될 때까지 파일이나 해당 공간을 해제하지 않습니다. 이는 파일 설명을 연 프로세스 수와 하드 링크 수에 관계없이 가능합니다.
파일이 열려 있는 동안 파일 수를 계산하고 현재 파일을 이름별로 계산할 수 있습니다. inode가 다르거나 수정 날짜가 다른 경우 삭제된 파일과 새 파일이 있습니다. 또는 삭제된 파일이 있지만 새 파일이 존재하지 않는 경우도 있습니다.
답변3
파일 설명자가 삭제된 파일 usr 을 참조하는지 bash에서 테스트합니다 /proc/pid/fd
. 아래 예.
$ ps -fp 52
UID PID PPID C STIME TTY TIME CMD
steve 52 7 0 18:07 tty1 00:00:00 tail -f x1.pdf
$ ls -l /proc/52/fd
total 0
lrwx------ 1 steve steve 0 Jun 13 18:07 0 -> /dev/tty1
lrwx------ 1 steve steve 0 Jun 13 18:07 1 -> /dev/tty1
lrwx------ 1 steve steve 0 Jun 13 18:07 2 -> /dev/tty1
lr-x------ 1 steve steve 0 Jun 13 18:07 3 -> /mnt/c/temp/x1.pdf (deleted)
$