Manière portable de trouver le numéro d'inode

10

Au début, j'ai utilisé stat -c %i file(pour aider à détecter la présence d'une prison ), qui semblait fonctionner sur n'importe quelle distribution Linux sous le soleil. Sur OS X ', je devais utiliser ls -i file | cut -d ' ' -f 1.

Existe-t-il un moyen de trouver le numéro d'inode d'un fichier dans un script shell qui est portable sur les plates-formes * nix et ne dépend pas des notoirement capricieux ls?

l0b0
la source
1
Vous pourriez être intéressé par, ou avoir de meilleures réponses, comment puis-je savoir que je cours dans un chroot? .
Gilles 'SO- arrête d'être méchant'
Pouvez-vous élaborer sur les «ls notoirement capricieux»?
jlliagre
@jlliagre: D'autres l'ont déjà fait mieux.
l0b0
D'accord, pour de tels fichiers, voir ma réponse.
jlliagre

Réponses:

11

Solution possible: La spécification POSIX pourls spécifie -i, alors peut-être qu'elle est portable. Quelqu'un connaît-il une implémentation populaire lsqui ne prend pas en charge cela ou l'imprime d'une manière différente de l'exemple suivant:

$ ls -di /
2 /
l0b0
la source
3
@jlliagre: Veuillez lire avant de poster. La statcommande ne fonctionnait pas sur OS X, ls -difonctionnait sur les deux.
l0b0
1
Même Busybox lsa -det -icomme fonctionnalités obligatoires (bien que lslui-même soit facultatif, comme tout le reste).
Gilles 'SO- arrête d'être méchant'
1
Le malentendu de Michael était précisément ce que je commentais. Cela ne vaut pas un commentaire assez grossier et immérité "lire avant de poster".
jlliagre
2
Il y a des exceptions à cela: lsavec des -ifront-pads avec des espaces sur au moins Solaris 10 (peut-être Solaris 11, je n'ai pas vérifié). Il semble que ce soit le comportement traditionnel remontant à la version 7 d'Unix, donc je soupçonne que de nombreuses versions d'entreprise * nix ont conservé ce comportement (je n'ai que Solaris 10 sous la main cependant). Si près que je sache, si vous utilisez quelque chose qui délimite correctement les champs dans des espaces blancs arbitraires (donc, non cut, mais par exemple awkou juste le propre fractionnement des champs du shell), il est portable de s'attendre à ce que la première chaîne non blanche soit l'inode nombre.
mtraceur
1
@ l0b0 Ouais. Cela nécessite un dévouement masochiste: un tas d'études / tests et de mémorisation pour des rendements constamment décroissants. C'est possible, du moins pour une certaine définition de "portable", mais ce n'est pas une expérience agréable.
mtraceur
2

Cela devrait être portable et fonctionner avec des noms de fichiers contenant des espaces, des sauts de ligne ou d'autres caractères étranges conduisant au comportement ls notoirement capricieux .

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

Pour augmenter la portabilité, vous pouvez également implémenter une fonction d'encapsulation spécifique à la plate-forme (appelée ici statinode()) autour de la statcommande qui peut être basée sur la sortie de uname -s(voir uname ).

ls serait nécessaire comme option de secours uniquement.

(
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
la source
0

statfait partie du paquet GNU Coreutils . OSX utilise une statimplémentation différente (vraisemblablement basée sur BSD) qui ne prend pas les mêmes arguments de ligne de commande.

Vous pouvez toujours installer GNU Coreutils sur OSX. Bien sûr, cela n'aide pas si vous avez besoin d'une solution qui fonctionne sur des systèmes OSX qui n'ont pas GNU Coreutils.

Ou, si je lis correctement la page de manuel OSX stat (1) , stat -f %i filesur OSX se comporte comme l' stat -c %i fileutilisation de la version Coreutils. (Déterminer quelle version de statvous avez est une autre affaire; vous pouvez essayer stat --version >/dev/null; si elle réussit, vous avez la version GNU Coreutils.)

La ls -disolution est plus portable et moins problématique, mais c'est une alternative.

Keith Thompson
la source
0

Une autre solution:

#!/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";

Vous pouvez probablement supposer en toute sécurité que Perl est installé.

Keith Thompson
la source
0

Similaire à l'approche de Jeff, statpourrait également être testé directement.

(
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
la source