GNU/Linux >> Tutoriales Linux >  >> Linux

Compruebe si un descriptor de archivo se refiere a un archivo eliminado (en Bash)

Para probar si un descriptor de archivo se refiere a un archivo normal que no tiene un enlace restante en ningún directorio del sistema de archivos, puede hacer un fstat() llame al sistema y verifique el número de enlaces (st_nlink field) en la estructura devuelta.

Con zsh , podrías hacerlo con su stat integrado:

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 (el shell GNU) no tiene equivalente, pero si está en un sistema GNU, es posible que tenga GNU stat en cuyo caso debería poder hacer algo como:

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 el kernel de su sistema operativo es Linux, un enfoque más portátil (para aquellos sistemas operativos que no tienen zsh y donde las utilidades principales no son de GNU), asumiendo que el sistema de archivos proc está montado en /proc podría ser usar ls en /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

Aquí duplicando el fd en 0 como en la solución anterior, por lo que funciona incluso si fd tiene el indicador close-on-exec (suponiendo que fd no sea 0 en primer lugar, pero fd 0 normalmente no tendría el indicador close-on-exec bandera).

Ese tipo de enfoque no funciona con el sistema de archivos falso que es procfs de Linux para verificar si un fd se abre en /proc/<some-pid>/cmdline se refiere a un proceso en vivo:

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

Mira cómo fstat().st_nlink devolvió 1 arriba (lo que significaría que el archivo todavía tenía un enlace a un directorio), mientras que cat de read() en el fd devolvió un error. Esa no es la semántica habitual del sistema de archivos.

En cualquier caso, para verificar si su padre aún se está ejecutando, puede llamar al getppid() que devolvería 1 o el pid del subsegador secundario si el padre muriera. En zsh , usarías $sysparams[ppid] (en el zsh/system módulo).

$ 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 , podrías usar ps -o ppid= -p "$BASHPID" en su lugar.

Otro enfoque sería crear una tubería entre padre e hijo y verificar con select /poll (o read -t0 en bash ) que todavía está activo.

Podría hacerse usando un coproc (agregado recientemente a bash ) en lugar 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

Que dan:

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

Construyendo sobre su enfoque previsto, y nuevamente asumiendo un kernel de Linux con procfs montado en /proc , también podrías hacer:

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

Usando [[ file1 -ef file2 ]] que comprueban si los archivos too tienen el mismo número de desarrollo e inodo (st_dev y st_ino devuelto por stat() ).

Eso parece funcionar con 5.6.0 pero, como hemos visto anteriormente, /proc no respeta la semántica habitual del sistema de archivos, no puedo garantizar que esté libre de carreras (el PID y el número de inodo posiblemente podrían haberse reutilizado) o que funcione en futuras versiones de Linux.


Su archivo original existe completamente sin cambios.

Una vez que se ha abierto un archivo por nombre, el descriptor de archivo que contiene su proceso cuenta como un enlace al archivo. El sistema no libera el archivo ni su espacio hasta que se hayan eliminado todos los enlaces:pueden ser cualquier cantidad de procesos que tengan una descripción de archivo abierta, además de cualquier cantidad de enlaces duros.

Puede indicar el archivo en el momento en que se abrió y indicar el archivo actual por nombre. Si son inodos diferentes o una fecha de modificación diferente, tiene un archivo eliminado y hay un archivo nuevo. O puede encontrar que tiene un archivo eliminado pero no existe uno nuevo.


Linux
  1. Cómo verificar la sintaxis de sudoers

  2. ¿Se puede conectar un script Bash a un archivo?

  3. El Bash'?

  4. ¿Cómo verificar la subcadena en Shell Script Bash?

  5. ¿Recuperar un archivo eliminado?

Comando de fuente Bash

Bash:Agregar al archivo

Sustitución de cadena en Bash

35 ejemplos de secuencias de comandos Bash

Script Bash (III)

Cómo verificar si existe un archivo o directorio en Bash Shell