Manera portátil de encontrar el número de inodo

10

Al principio solía stat -c %i file(para ayudar a detectar la presencia de una cárcel ), que parecía funcionar en cualquier distribución de Linux bajo el sol. En OS X 'tuve que usar ls -i file | cut -d ' ' -f 1.

¿Hay alguna forma de encontrar el número de inodo de un archivo en un script de shell que es portátil en las plataformas * nix y no depende de los notoriamente caprichosos ls?

l0b0
fuente
1
Puede interesarle o tener mejores respuestas para: ¿Cómo puedo decir que estoy corriendo en un chroot? .
Gilles 'SO- deja de ser malvado'
¿Puedes dar más detalles sobre el "notoriamente caprichoso ls"?
jlliagre
@jlliagre: Otros ya lo han hecho mejor.
l0b0
Bien, para tales archivos, vea mi respuesta.
jlliagre

Respuestas:

11

Posible solución: la especificación POSIX parals especifica -i, por lo que tal vez sea portátil. ¿Alguien sabe de una implementación popular lsque no sea compatible con esto, o la imprima de manera diferente al siguiente ejemplo:

$ ls -di /
2 /
l0b0
fuente
3
@jlliagre: Lea antes de publicar. El statcomando no funcionó en OS X, ls -difuncionó en ambos.
l0b0
1
Incluso Busybox lstiene -dy -icomo características obligatorias (aunque en lssí mismo es opcional, como todo lo demás).
Gilles 'SO- deja de ser malvado'
1
El malentendido de Michael fue precisamente lo que estaba comentando. No vale un comentario bastante grosero e inmerecido de "leer antes de publicar".
jlliagre
2
No hay excepciones a esto: lscon -ifront-almohadillas con espacios en al menos Solaris 10 (posiblemente Solaris 11, no he comprobado). Parece que este era el comportamiento tradicional desde la versión 7 de Unix, por lo que sospecho que muchos de los sabores corporativos * nix mantuvieron este comportamiento (aunque solo tengo Solaris 10 disponible). Tan cerca como puedo decir, si usa algo que delimita adecuadamente los campos en espacios en blanco arbitrarios (por lo tanto, no cut, pero por ejemplo awko solo la división de campos del propio shell), es portátil esperar que la primera cadena que no sea un espacio en blanco sea el inodo número.
mtraceur
1
@ l0b0 Sí. Requiere dedicación masoquista: un montón de estudio / prueba y memorización para rendimientos constantemente decrecientes. Es posible, al menos para alguna definición de "portátil", pero no es una experiencia agradable.
mtraceur
2

Esto debería ser portátil y funcionar con nombres de archivos que contengan espacios, líneas nuevas u otros caracteres extraños que conduzcan al comportamiento ls notoriamente caprichoso .

filename="whatever file name"
find . -name "$filename" -exec sh -c 'ls -di "$0" | head -1' {} \;
jlliagre
fuente
1

Para aumentar la portabilidad, también puede implementar una función de contenedor específica de la plataforma (aquí llamada statinode()) alrededor del statcomando que puede basarse en la salida de uname -s(ver uname ).

ls sería necesario solo como una opción alternativa.

(
shopt -s nocasematch nullglob    # using Bash
case "$(uname -s)" in
   # nocasematch alternative
   #[Ll][Ii][Ni][Uu][Xx]   )  statinode() { stat -c '%i' "$@"; return 0; };;
   "Linux"   )      statinode() { stat -c '%i' "$@"; return 0; };;
   "Darwin"  )      statinode() { stat -f '%i' "$@"; return 0; };;
   "FreeBSD" )      statinode() { stat -f '%i' "$@"; return 0; };;
           * )      statinode() { ls -id "$@" | cut -d ' ' -f 1; return 0; };;
esac
#export -f statinode
statinode / / / /
shopt -u nocasematch nullglob
)
jeff
fuente
0

states parte del paquete GNU Coreutils . OSX usa una statimplementación diferente (presumiblemente una basada en BSD) que no toma los mismos argumentos de línea de comandos.

Siempre puede instalar GNU Coreutils en OSX. Por supuesto, eso no ayuda si necesita una solución que funcione en sistemas OSX que no tengan GNU Coreutils.

O, si estoy leyendo la página de manual OSX stat (1) correctamente, stat -f %i fileen OSX se comporta como si stat -c %i fileusara la versión Coreutils. (Determinar qué versión stattiene es otra cuestión; podría intentarlo stat --version >/dev/null; si tiene éxito, tiene la versión GNU Coreutils).

La ls -disolución es más portátil y menos problemática, pero esta es una alternativa.

Keith Thompson
fuente
0

Otra solución:

#!/usr/bin/perl

use strict;
use warnings;

die "Usage: $0 filename\n" if scalar @ARGV != 1;
my $file = $ARGV[0];
my @stat = stat $file;
die "$file: $!\n" if not @stat;
print "$stat[1]\n";

Probablemente pueda asumir con seguridad que Perl está instalado.

Keith Thompson
fuente
0

Similar al enfoque de jeff, también statpodría probarse directamente.

(
if (stat -c '%i' / 1>/dev/null 2>&1; exit $?); then
   statinode() { stat -c '%i' "$@"; return 0; }
elif (stat -f '%i' / 1>/dev/null 2>&1; exit $?); then
   statinode() { stat -f '%i' "$@"; return 0; }
elif test -n "$(exec 2>/dev/null; ls -id / | cut -d ' ' -f 1)"; then
   statinode() { ls -id "$@" | cut -d ' ' -f 1; return 0; }
else
   echo 'Could not create statinode(). Exiting ...' && exit 1
fi
# export -f statinode
statinode / / / /
declare -f statinode
)
ianc
fuente