查找索引节点编号的便携式方法


10

最初,我使用stat -c %i file(以帮助检测是否存在监牢),它似乎可以在阳光下的任何Linux发行版上运行。在OS X上,我必须使用ls -i file | cut -d ' ' -f 1

是否有某种方法可以在可跨* nix平台移植且不依赖于反复无常的shell脚本中查找文件的inode编号ls


1
您可能对如何知道我在chroot中运行感兴趣,或者有更好的答案
吉尔(Gilles)“所以,别再邪恶了”,

您能否详细说明“臭名昭著的ls”?
jlliagre 2011年

@jlliagre:其他人做了好多了。
l0b0 2011年

好的,有关此类文件,请参阅我的回复。
jlliagre 2011年

Answers:


11

可能的解决方案:指定的POSIX规范ls-i,因此可能是可移植的。难道一个流行的实现的任何人都知道ls这不支持这一点,或把它打印从下面的例子中以不同的方式:

$ ls -di /
2 /

3
@jlliagre:请在发布之前阅读。该stat命令在OS X ls -di上不起作用,在这两者上都起作用。
l0b0 2011年

1
甚至Busybox ls也具有-d-i作为必选功能(尽管ls它本身是可选的,与其他所有功能一样)。
吉尔斯(Gilles)'所以

1
迈克尔的误会恰恰是我的评论。它不值得粗鲁和不当的“发布前阅读”评论。
jlliagre 2011年

2
例外情况:ls-i上至少的Solaris 10(可能的Solaris 11,我没有检查)前垫用空格。看起来这是回溯到Unix 7的传统行为,因此我怀疑很多公司的* nix风格都保持了这种行为(不过我手上只有Solaris 10)。据我所知,如果您使用正确地描绘了任意空格中的字段的东西(cut例如,不是,而是awk仅是shell自己的字段拆分),则可以很方便地将第一个非空白字符串作为索引节点数。
mtraceur '16

1
@ l0b0是的。它需要自虐的奉献精神:一堆学习/测试和记忆,以不断减少回报。可能,至少对于“便携式”的某种定义,但这不是令人愉快的体验。
mtraceur '16

2

这应该是可移植的,并且可以使用包含空格,换行符或其他奇怪字符的文件名,从而导致臭名昭著的 ls行为。

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

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

statGNU Coreutils软件包的一部分。OSX使用不同的stat实现(可能是基于BSD的实现),该实现不需要相同的命令行参数。

您总是可以在OSX上安装GNU Coreutils。当然,如果您需要一种适用于没有GNU Coreutils的OSX系统的解决方案,那将无济于事。

或者,如果我正确阅读了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

与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
)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.