GNU/Linux >> Tutoriels Linux >  >> Linux

Vérifier si un descripteur de fichier fait référence à un fichier supprimé (dans Bash)

Pour tester si un descripteur de fichier fait référence à un fichier normal qui n'a plus de lien dans aucun répertoire du système de fichiers, vous pouvez créer un fstat() appel système dessus et vérifier le nombre de liens (st_nlink champ) dans la structure renvoyée.

Avec zsh , vous pourriez le faire avec son stat intégré :

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 (le shell GNU) n'a pas d'équivalent, mais si vous êtes sur un système GNU, vous pourriez avoir GNU stat dans ce cas, vous devriez pouvoir faire quelque chose comme :

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

Si votre noyau de système d'exploitation est Linux, une approche plus portable (pour les systèmes d'exploitation qui n'ont pas zsh et où les utilitaires principaux ne proviennent pas de GNU), en supposant que le système de fichiers proc est monté sur /proc pourrait être d'utiliser ls le /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

Ici, dupliquer le fd sur 0 comme dans la solution précédente, donc cela fonctionne même si fd a le drapeau close-on-exec (en supposant que fd n'est pas 0 en premier lieu, mais fd 0 n'aurait normalement pas le close-on-exec drapeau).

Ce genre d'approche ne fonctionne pas avec le faux système de fichiers qu'est le procfs de Linux pour vérifier si un fd s'ouvre sur /proc/<some-pid>/cmdline fait référence à un processus en direct :

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

Découvrez comment fstat().st_nlink renvoyé 1 ci-dessus (ce qui signifierait que le fichier avait toujours un lien vers un répertoire), tandis que cat est read() sur le fd a renvoyé une erreur. Ce n'est pas la sémantique habituelle du système de fichiers.

Dans tous les cas, pour vérifier si ton parent court toujours, tu peux appeler le getppid() qui renverrait 1 ou le pid du sous-moissonneur enfant si le parent mourait. En zsh , vous utiliseriez $sysparams[ppid] (dans le zsh/system module).

$ sh -c 'zsh -c '\''zmodload zsh/system
                    print $PPID $sysparams[ppid]
                    sleep 2; print $PPID $sysparams[ppid]
                '\'' & sleep 1'
14585 14585
$ 14585 1

En bash , vous pouvez utiliser ps -o ppid= -p "$BASHPID" à la place.

Une autre approche serait de créer un tuyau entre le parent et l'enfant et de vérifier avec select /poll (ou read -t0 en bash ) qu'il est toujours actif.

Peut être fait en utilisant un coproc (ajouté récemment à bash ) au lieu de & .

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

Ce qui donne :

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

Construire sur votre approche envisagée, et encore une fois en supposant un noyau Linux avec procfs monté sur /proc , vous pouvez également faire :

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

Utilisation de [[ file1 -ef file2 ]] qui vérifient si les fichiers too ont le même numéro dev et inode (st_dev et st_ino renvoyé par stat() ).

Cela semble fonctionner avec 5.6.0 mais comme nous l'avons vu ci-dessus, /proc ne respecte pas la sémantique habituelle du système de fichiers, je ne peux pas garantir qu'il est sans course (le PID et le numéro d'inode auraient pu être réutilisés) ou qu'il fonctionnerait dans les futures versions de Linux.


Votre fichier d'origine existe complètement inchangé.

Une fois qu'un fichier a été ouvert par son nom, le descripteur de fichier que contient votre processus compte comme un lien vers le fichier. Le système ne libère pas le fichier ou son espace tant que tous les liens n'ont pas été supprimés :il peut s'agir de n'importe quel nombre de processus pour lesquels une description de fichier est ouverte, plus n'importe quel nombre de liens physiques.

Vous pouvez stat le fichier au moment où il a été ouvert, et stat le fichier actuel par son nom. S'il s'agit d'inodes différents ou d'une date de modification différente, vous avez un fichier supprimé et il y a un nouveau fichier. Ou vous constaterez peut-être que vous avez un fichier supprimé mais qu'il n'en existe pas de nouveau.


Linux
  1. Comment vérifier la syntaxe sudoers

  2. La fête ?

  3. Script Bash :vérifier si un fichier est un fichier texte ?

  4. Comment vérifier la sous-chaîne dans Shell Script Bash?

  5. Récupérer un fichier supprimé ? ?

Commande de source bash

Bash :ajouter au fichier

Remplacement de chaîne dans Bash

35 exemples de scripts bash

Script bash (III)

Comment vérifier si un fichier ou un répertoire existe dans Bash Shell