GNU/Linux >> Belajar Linux >  >> Linux

Periksa apakah filedescriptor merujuk ke file yang dihapus (di Bash)

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.


Linux
  1. Bisakah Skrip Bash Dihubungkan ke File?

  2. Basa'?

  3. Bash Script:Periksa Apakah File Adalah File Teks?

  1. Bagaimana cara memeriksa sintaks sudoers

  2. Bagaimana cara memeriksa syslog di Bash di Linux?

  3. Bagaimana cara memeriksa apakah suatu file kosong di Bash?

  1. Bagaimana Cara Memeriksa Kemajuan Running Cp?

  2. Bagaimana Cara Memeriksa Substring Di Shell Script Bash?

  3. Pulihkan File yang Dihapus??