Maneira portátil de encontrar o número do inode

10

No começo, eu usei stat -c %i file(para ajudar a detectar a presença de uma prisão ), que parecia funcionar em qualquer distribuição Linux sob o sol. No OS X 'eu tive que usar ls -i file | cut -d ' ' -f 1.

Existe alguma maneira de encontrar o número de inode de um arquivo em um script de shell que seja portátil em plataformas * nix e não dependa do notoriamente caprichoso ls?

l0b0
fonte
1
Você pode estar interessado ou ter melhores respostas para: Como saber se estou executando um chroot? .
Gilles 'SO- stop be evil'
Você pode elaborar sobre os "sl notoriamente caprichosos"?
Jlliagre
@ jlliagre: Outros já fizeram isso melhor.
l0b0
Ok, para esses arquivos, veja minha resposta.
Jlliagre

Respostas:

11

Solução possível: a especificação POSIX parals especifica -i, talvez seja portátil. Alguém sabe de uma implementação popular da lsqual não oferece suporte a isso ou a imprime de maneira diferente do exemplo a seguir:

$ ls -di /
2 /
l0b0
fonte
3
@ jlliagre: Por favor, leia antes de postar. O statcomando não funcionou no OS X, ls -difuncionou em ambos.
L0b0
1
Até o Busybox lspossui -de -icomo recursos obrigatórios (embora lsele próprio seja opcional, como todo o resto).
Gilles 'SO- stop be evil'
1
O mal-entendido de Michael era exatamente o que eu estava comentando. Não vale um comentário "rude antes de postar" bastante rude e imerecido.
Jlliagre
2
Não são excepções a esta: lscom -ifrente-pads com espaços em pelo menos Solaris 10 (possivelmente Solaris 11, eu não tenho verificado). Parece que esse era o comportamento tradicional do Unix versão 7, então eu suspeito que muitos dos sabores corporativos * nix mantiveram esse comportamento (eu só tenho o Solaris 10 em mãos). Tão perto quanto eu posso dizer, se você usar algo que delineia adequadamente os campos em espaço em branco arbitrário (então, não cut, mas, por exemplo, awkou apenas a própria divisão de campo do shell), é portátil esperar que a primeira string que não seja em branco seja o inode número.
Mtraceur # 9/16
1
@ l0b0 Sim. Requer dedicação masoquista: um monte de estudo / teste e memorização para retornos constantemente decrescentes. É possível, pelo menos para alguma definição de "portátil", mas não é uma experiência agradável.
Mtraceur # 9/16
2

Isso deve ser portátil e funcionar com nomes de arquivos que contenham espaços, novas linhas ou outros caracteres estranhos, levando ao comportamento notoriamente caprichoso do ls.

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

Para aumentar a portabilidade, você também pode implementar uma função de wrapper específica da plataforma (chamada aqui statinode()) em torno do statcomando que pode basear-se na saída de uname -s(consulte uname ).

ls seria necessário apenas como uma opção de fallback.

(
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
fonte
0

statfaz parte do pacote GNU Coreutils . O OSX usa uma statimplementação diferente (presumivelmente baseada em BSD) que não aceita os mesmos argumentos da linha de comando.

Você sempre pode instalar o GNU Coreutils no OSX. Claro que isso não ajuda se você precisar de uma solução que funcione em sistemas OSX que não possuam GNU Coreutils.

Ou, se estou lendo a página de manual OSX stat (1) corretamente, stat -f %i fileno OSX se comporta como stat -c %i fileusar a versão Coreutils. (Determinar qual versão statvocê tem é outra questão; você pode tentar stat --version >/dev/null; se for bem-sucedido, você tem a versão GNU Coreutils.)

A ls -disolução é mais portátil e com menos problemas, mas essa é uma alternativa.

Keith Thompson
fonte
0

Outra solução:

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

Provavelmente, você pode assumir com segurança que o Perl está instalado.

Keith Thompson
fonte
0

Semelhante à abordagem de jeff, também statpoderia ser testado diretamente.

(
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
fonte