Untuk menguji apakah deskriptor file merujuk ke file biasa yang tidak memiliki tautan tersisa di direktori mana pun pada sistem file, Anda dapat membuat fstat()
panggil sistem dan periksa jumlah tautan (st_nlink
bidang) dalam struktur yang dikembalikan.
Dengan zsh
, Anda dapat melakukannya dengan stat
bawaan:
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
(cangkang GNU) tidak memiliki persamaan, tetapi jika Anda menggunakan sistem GNU, Anda mungkin memiliki GNU stat
dalam hal ini Anda harus dapat melakukan sesuatu seperti:
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
Jika kernel OS Anda adalah Linux, pendekatan yang lebih portabel (untuk OS yang tidak memiliki zsh
dan di mana utilitas inti bukan dari GNU), dengan asumsi sistem file proc dipasang pada /proc
bisa menggunakan ls
pada /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
Di sini menduplikasi fd on 0 seperti pada solusi sebelumnya, sehingga berfungsi bahkan jika fd memiliki flag close-on-exec (dengan asumsi fd bukan 0 sejak awal, tetapi fd 0 biasanya tidak memiliki close-on-exec bendera).
Pendekatan semacam itu tidak bekerja dengan sistem file palsu yang merupakan procfs Linux untuk memeriksa apakah fd terbuka di /proc/<some-pid>/cmdline
mengacu pada proses langsung:
$ zsh -c 'zmodload zsh/stat; (sleep 1; stat -f0 +nlink; cat) < /proc/$$/cmdline &'
$ 1
cat: -: No such process
Lihat bagaimana fstat().st_nlink
mengembalikan 1 di atas (yang berarti file tersebut masih memiliki tautan ke direktori), sedangkan cat
read()
pada fd mengembalikan kesalahan. Itu bukan semantik sistem file biasa.
Bagaimanapun, untuk memeriksa apakah orang tua Anda masih berjalan, Anda dapat memanggil getppid()
yang akan mengembalikan 1 atau pid subreaper anak jika induknya meninggal. Di zsh
, Anda akan menggunakan $sysparams[ppid]
(dalam zsh/system
modul).
$ sh -c 'zsh -c '\''zmodload zsh/system
print $PPID $sysparams[ppid]
sleep 2; print $PPID $sysparams[ppid]
'\'' & sleep 1'
14585 14585
$ 14585 1
Di bash
, Anda dapat menggunakan ps -o ppid= -p "$BASHPID"
sebagai gantinya.
Pendekatan lain adalah membuat pipa antara induk dan anak dan periksa dengan select
/poll
(atau read -t0
di bash
) bahwa itu masih menyala.
Bisa dilakukan dengan menggunakan coproc
(baru saja ditambahkan ke bash
) bukan &
.
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
Yang memberikan:
$ bash ./that-script
parent still there
$ parent gone
Membangun pendekatan yang Anda impikan, dan sekali lagi mengasumsikan kernel Linux dengan procfs
terpasang pada /proc
, Anda juga dapat melakukan:
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
Menggunakan [[ file1 -ef file2 ]]
yang memeriksa apakah file juga memiliki nomor dev dan inode yang sama (st_dev
dan st_ino
dikembalikan oleh stat()
).
Tampaknya bekerja dengan 5.6.0 tetapi seperti yang telah kita lihat di atas /proc
tidak menghormati semantik sistem file yang biasa, saya tidak dapat menjamin itu bebas ras (PID dan nomor inode mungkin telah digunakan kembali) atau itu akan berfungsi di versi Linux yang akan datang.
File asli Anda sama sekali tidak berubah.
Setelah file dibuka berdasarkan nama, deskriptor file yang disimpan oleh proses Anda dianggap sebagai tautan ke file tersebut. Sistem tidak melepaskan file atau ruangnya hingga semua tautan dihapus:itu bisa berupa sejumlah proses yang membuka deskripsi file untuknya, ditambah sejumlah tautan keras.
Anda dapat stat file pada saat dibuka, dan stat file saat ini dengan nama. Jika mereka adalah inode yang berbeda atau tanggal modifikasi yang berbeda, Anda memiliki file yang dihapus dan ada file baru. Atau Anda mungkin menemukan bahwa Anda memiliki file yang dihapus tetapi tidak ada yang baru.