Портативный способ найти inode число

Основное различие между псевдонимами и функциями - то, что псевдонимы не берут аргументы ¹, но функции делают. Когда Вы пишете что-то как alias l='ls --color', l foo расширен до ls --color foo; Вы не можете захватить foo в расширение псевдонима и делают что-то другое с ним способ, которым можно сделать с функцией. См. также, Как передать параметр для искажения?.

Псевдонимы ищутся перед функциями: если у Вас есть и функция и названный псевдоним foo, foo вызывает псевдоним. (Если псевдоним foo расширяется, это временно заблокировано, который делает вещи как alias ls='ls --color' работа. Кроме того, можно обойти псевдоним в любое время путем выполнения \foo.) Я не ожидал бы видеть измеримое различие в производительности все же.

Функции и автономные сценарии имеют главным образом подобные возможности; вот несколько различий, о которых я могу думать:

  • Функция работает в среде оболочки; сценарий работает в отдельном процессе. Поэтому функция может изменить среду оболочки: определите переменные среды, измените текущий каталог и т.д. Автономный сценарий не может сделать этого.
  • Функция должна быть записана на языке оболочки, в которой Вы хотите использовать его. Сценарий может быть записан на любом языке.
  • Функции загружаются, когда они определяются. Сценарии загружаются каждый раз, когда они вызываются. Это имеет несколько последствий:
    • При изменении сценария Вы получаете новую версию в следующий раз, когда Вы вызываете ее. При изменении определения функции необходимо перезагрузить определение.
    • Функции быстрее в в большой степени загруженных системах.
    • Если у Вас будет много функций, которые Вы не можете использовать, то они поднимут память. Ksh и zsh, но я думаю не, колотят, имеют форму функциональной автозагрузки.

Что-то это является промежуточным между функцией и автономным сценарием, является отрывком сценария, который Вы читаете с source или . встроенный. Как функция, это может изменить среду оболочки и должно быть записано на языке оболочки. Как сценарий, это загружается каждый раз, когда это вызывается и только.

¹ Да, я знаю, это не относится к tcsh.

10
09.11.2011, 21:54
6 ответов

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

$ ls -di /
2 /
11
27.01.2020, 20:01
  • 1
    @jlliagre: читайте перед регистрацией. stat команда не работала над OS X, ls -di работавший на обоих. –  l0b0 08.11.2011, 16:54
  • 2
    Даже Busybox ls имеет -d и -i как обязательные функции (хотя ls самостоятельно является дополнительным, как все остальное). –  Gilles 'SO- stop being evil' 09.11.2011, 02:00
  • 3
    Michael было точно, что я комментировал. Это не делает стоящий довольно грубого и незаслуженного "чтения прежде, чем добавить" комментарий. –  jlliagre 10.11.2011, 02:32
  • 4
    Существуют исключения к этому: ls с -i передние клавиатуры с пробелами, по крайней мере, на Солярисе 10 (возможно Солярис 11, я не проверил). Похоже, что это было традиционным поведением, возвращающимся к версии 7 Unix, таким образом, я подозреваю, что много корпоративных *отклоняет разновидности, сохраненные этим поведением (у меня только есть Солярис 10 под рукой хотя). Столь рядом, как я могу сказать, если Вы используете что-то, что правильно формирует рисунок полей в произвольном пробеле (так, нет cut, но например awk или просто собственное разделение поля оболочки), это портативно, чтобы ожидать, что первая непробельная строка будет inode числом. –  mtraceur 09.10.2016, 08:30
  • 5
    @l0b0 Да. Это требует мазохистского посвящения: набор исследования/тестирования и запоминания для постоянно убывающей доходности. Это возможно, по крайней мере, для некоторого определения "портативных", но это не приятное впечатление. –  mtraceur 09.10.2016, 20:53

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

filename="whatever file name"
find . -name "$filename" -exec sh -c 'ls -di "$0" | head -1' {} \;
2
27.01.2020, 20:01

Для увеличения мобильности, можно также реализовать определенную для платформы функцию обертки (здесь названный 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
)
1
27.01.2020, 20:01

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

#!/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
27.01.2020, 20:01

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

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

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

ls -di решение является более портативным и меньше проблемы, но это - альтернатива.

0
27.01.2020, 20:01

Подобный подходу jeff, 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
)
0
27.01.2020, 20:01

Теги

Похожие вопросы