ファイル記述子が、ファイル システムのどのディレクトリにもリンクが残っていない通常のファイルを参照しているかどうかをテストするには、fstat()
を作成します。 その上でシステムコールを呼び出し、リンクの数を確認します (st_nlink
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
OS カーネルが Linux の場合、より移植性の高いアプローチ (zsh
を持たない OS の場合) proc ファイルシステムが /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
ここでは、前のソリューションのように 0 で fd を複製するため、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
のやり方を見る cat
の間、上記の 1 が返されました (これは、ファイルがまだディレクトリへのリンクを持っていることを意味します)。 の read()
fd でエラーが返されました。これは、通常のファイル システム セマンティックではありません。
いずれにせよ、親がまだ実行中かどうかを確認するには、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
bash
で ) まだ稼働中です。
coproc
を使用して実行できます (最近 bash
に追加されたばかりです ) &
の代わりに .
background_with_pipe() {
coproc "[email protected]" {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
想定したアプローチを構築し、再び procfs
の Linux カーネルを想定 /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 ]]
の使用 too ファイルが同じ dev および inode 番号 (st_dev
) を持っているかどうかをチェックします。 と st_ino
stat()
によって返されます ).
これは 5.6.0 で動作するようですが、上記で見たように /proc
通常のファイルシステムのセマンティクスを尊重しません。競合がないこと (PID と inode 番号が再利用された可能性があります) や、将来の Linux バージョンで動作することを保証できません。
元のファイルはまったく変更されずに存在します。
ファイルが名前で開かれると、プロセスが保持するファイル記述子はファイルへのリンクとしてカウントされます。すべてのリンクが削除されるまで、システムはファイルまたはそのスペースを解放しません。それらは、ファイルの説明が開いている任意の数のプロセスと、任意の数のハード リンクである可能性があります。
ファイルを開いた時点で stat し、現在のファイルを名前で stat することができます。それらが異なる i ノードまたは異なる変更日である場合、削除されたファイルがあり、新しいファイルがあります。または、ファイルが削除されているのに、新しいファイルが存在しないことに気付くかもしれません。