Портативный способ найти номер инода

10

Сначала я использовал stat -c %i file(чтобы обнаружить присутствие тюрьмы ), который, казалось, работал на любом дистрибутиве Linux под солнцем. На OS X'е пришлось пользоваться ls -i file | cut -d ' ' -f 1.

Есть ли способ найти номер индекса файла в сценарии оболочки, который переносим на платформы * nix и не зависит от общеизвестно капризного ls?

l0b0
источник
1
Возможно, вас заинтересуют или у вас есть лучшие ответы на вопрос: Как мне узнать, что я работаю в chroot? ,
Жиль "ТАК - перестань быть злым"
Можете ли вы рассказать о "заведомо капризном"?
Jlliagre
@jlliagre: Другие уже сделали это лучше.
2010 г.
Хорошо, для таких файлов, смотрите мой ответ.
Jlliagre

Ответы:

11

Возможное решение: спецификация POSIX дляls спецификаций -i, поэтому, возможно, она переносима. Кто-нибудь знает о популярной реализации, lsкоторая не поддерживает это, или печатает ее иначе, чем в следующем примере:

$ ls -di /
2 /
l0b0
источник
3
@jlliagre: Пожалуйста, прочитайте перед публикацией. Команда statне работала на OS X, ls -diработала на обоих.
10
1
Даже Busybox lsимеет -dи в -iкачестве обязательных функций (хотя lsсам по себе является необязательным, как и все остальное).
Жиль "ТАК - перестань быть злым"
1
Непонимание Майкла было именно тем, что я комментировал. Это не стоит довольно грубого и незаслуженного комментария «прочитай перед публикацией».
Jlliagre
2
Там являются исключениями из этого правила : lsс -iпередними подушечками с пробелами по крайней мере , Solaris 10 (возможно , Solaris 11, я не проверил). Похоже, что это было традиционное поведение, восходящее к Unix версии 7, поэтому я подозреваю, что многие корпоративные разновидности * nix сохранили это поведение (хотя у меня только Solaris 10 под рукой). Насколько я могу судить, если вы используете что-то, что правильно разграничивает поля в произвольном пробеле (то есть, нет cut, но, например, awkили просто собственное разбиение поля оболочки), можно ожидать, что первая непробельная строка будет индексом число.
mtraceur
1
@ l0b0 Да. Это требует мазохистской преданности: куча изучения / тестирования и запоминания для постоянно уменьшающейся отдачи. Это возможно, по крайней мере, для некоторого определения «портативный», но это не приятный опыт.
mtraceur
2

Он должен быть переносимым и работать с именами файлов, содержащими пробелы, символы новой строки или другие нечетные символы, что приводит к общеизвестному капризному поведению ls.

filename="whatever file name"
find . -name "$filename" -exec sh -c 'ls -di "$0" | head -1' {} \;
jlliagre
источник
1

Для повышения переносимости вы также можете реализовать платформо-зависимую функцию-оболочку (здесь она вызывается statinode()) вокруг statкоманды, которая может быть основана на выводе uname -s(см. Uname ).

ls будет необходим только в качестве запасного варианта.

(
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
)
Джефф
источник
0

statявляется частью пакета GNU Coreutils . OSX использует другую statреализацию (предположительно основанную на BSD), которая не принимает те же аргументы командной строки.

Вы всегда можете установить GNU Coreutils на OSX. Конечно, это не поможет, если вам нужно решение, которое работает на системах OSX, не имеющих GNU Coreutils.

Или, если я правильно читаю man-страницу OSX stat (1) , stat -f %i fileв OSX ведет себя как stat -c %i fileпри использовании версии Coreutils. (Определить, какая у statвас версия , это другое дело; вы можете попробовать stat --version >/dev/null; в случае успеха у вас есть версия GNU Coreutils.)

ls -diРешение более компактно и меньше хлопот, но это альтернатива.

Кит Томпсон
источник
0

Другое решение:

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

Вы, вероятно, можете смело предположить, что Perl установлен.

Кит Томпсон
источник
0

Подобно подходу Джеффа, statможет быть также проверено напрямую.

(
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
источник