GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Prüfen, ob ein Dateideskriptor auf eine gelöschte Datei verweist (in Bash)

Um zu testen, ob sich ein Dateideskriptor auf eine reguläre Datei bezieht, die in keinem Verzeichnis des Dateisystems einen verbleibenden Link hat, könnten Sie einen fstat() erstellen System rufen Sie darauf auf und überprüfen Sie die Anzahl der Links (st_nlink Feld) in der zurückgegebenen Struktur.

Mit zsh , könnten Sie es mit seinem stat tun eingebaut:

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 (die GNU-Shell) hat kein Äquivalent, aber wenn Sie sich auf einem GNU-System befinden, haben Sie möglicherweise GNU stat In diesem Fall sollten Sie in der Lage sein, Folgendes zu tun:

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

Wenn Ihr Betriebssystem-Kernel Linux ist, ist ein portablerer Ansatz (für die Betriebssysteme, die nicht über zsh und wo die Kerndienstprogramme nicht von GNU stammen), vorausgesetzt, das proc-Dateisystem ist auf /proc gemountet könnte sein, ls zu verwenden auf /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

Hier wird fd wie in der vorherigen Lösung auf 0 dupliziert, sodass es auch dann funktioniert, wenn fd das close-on-exec-Flag hat (vorausgesetzt, fd ist von vornherein nicht 0, aber fd 0 hätte normalerweise kein close-on-exec Flagge).

Diese Art von Ansatz funktioniert nicht mit dem gefälschten Dateisystem, das die procfs von Linux sind, um zu prüfen, ob ein fd auf /proc/<some-pid>/cmdline geöffnet ist bezieht sich auf einen Live-Prozess:

$ zsh -c 'zmodload zsh/stat; (sleep 1; stat -f0 +nlink; cat) < /proc/$$/cmdline &'
$ 1
cat: -: No such process

Siehe wie fstat().st_nlink gab oben 1 zurück (was bedeuten würde, dass die Datei noch einen Link zu einem Verzeichnis hatte), während cat ist read() auf dem fd gab einen Fehler zurück. Das ist keine übliche Dateisystem-Semantik.

In jedem Fall können Sie überprüfen, ob Ihr Elternteil noch läuft, indem Sie getppid() anrufen was 1 oder die PID des untergeordneten Subreapers zurückgeben würde, wenn der Elternteil starb. In zsh , würden Sie $sysparams[ppid] verwenden (im 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

In bash , könnten Sie ps -o ppid= -p "$BASHPID" verwenden stattdessen.

Ein anderer Ansatz wäre, eine Pipe zwischen Eltern und Kind zu erstellen und mit select zu überprüfen /poll (oder read -t0 in bash ), dass es noch läuft.

Könnte mit einem coproc erfolgen (erst kürzlich zu bash hinzugefügt ) statt & .

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

Welche geben:

$ bash ./that-script
parent still there
$ parent gone

Bauen Sie auf Ihrem geplanten Ansatz auf und gehen Sie wieder von einem Linux-Kernel mit procfs aus montiert auf /proc , könnten Sie auch Folgendes tun:

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

Mit [[ file1 -ef file2 ]] die prüfen, ob die Too-Dateien die gleiche Dev- und Inode-Nummer haben (st_dev und st_ino zurückgegeben von stat() ).

Das scheint mit 5.6.0 zu funktionieren, aber wie wir oben gesehen haben, /proc die übliche Dateisystem-Semantik nicht beachtet, ich kann nicht garantieren, dass es rassenfrei ist (PID und Inode-Nummer könnten möglicherweise wiederverwendet worden sein) oder dass es in zukünftigen Linux-Versionen funktionieren würde.


Ihre Originaldatei existiert vollständig unverändert.

Sobald eine Datei namentlich geöffnet wurde, zählt der Dateideskriptor, den Ihr Prozess enthält, als Link zu der Datei. Das System gibt die Datei oder ihren Speicherplatz nicht frei, bis alle Verknüpfungen gelöscht wurden:Dies können beliebig viele Prozesse sein, die eine Dateibeschreibung dafür geöffnet haben, plus eine beliebige Anzahl fester Links.

Sie könnten die Datei zum Zeitpunkt des Öffnens und die aktuelle Datei nach Namen angeben. Wenn es sich um unterschiedliche Inodes oder ein unterschiedliches Änderungsdatum handelt, haben Sie eine gelöschte Datei und eine neue Datei. Oder Sie stellen fest, dass Sie eine gelöschte Datei haben, aber keine neue existiert.


Linux
  1. So überprüfen Sie die Syntax von Sudoers

  2. Kann ein Bash-Skript mit einer Datei verknüpft werden?

  3. Die Bash‘?

  4. Bash-Skript:Prüfen, ob eine Datei eine Textdatei ist?

  5. Eine gelöschte Datei wiederherstellen??

Bash-Quellbefehl

Bash:An Datei anhängen

Ersetzen von Zeichenfolgen in Bash

35 Bash-Skriptbeispiele

Bash-Scripting(III)

So überprüfen Sie, ob eine Datei oder ein Verzeichnis in der Bash-Shell vorhanden ist