At first I used stat -c %i file (to help detect the presence of a jail), which seemed to work on any Linux distribution under the sun. On OS X’ I had to use ls -i file | cut -d ' ' -f 1.
Is there some way to find the inode number of a file in a shell script which is portable across *nix platforms and does not depend on the notoriously capricious ls?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Possible solution: The POSIX spec for ls specifies -i, so maybe it’s portable. Does anyone know of a popular implementation of ls which does not support this, or prints it in a different way from the following example:
$ ls -di / 2 /
Method 2
This should be portable and work with file names containing spaces, newlines or other odd characters leading to the notoriously capricious ls behavior.
filename="whatever file name"
find . -name "$filename" -exec sh -c 'ls -di "$0" | head -1' {} ;
Method 3
To increase portability you may also implement a platform-specific wrapper function (here called statinode()) around the stat command that can be based on the output of uname -s (see uname).
ls would be needed as a fallback option only.
(
shopt -s nocasematch nullglob # using Bash
case "$(uname -s)" in
# nocasematch alternative
#[Ll][Ii][Ni][Uu][Xx] ) statinode() { stat -c '%i' "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f0d4b0">[email protected]</a>"; return 0; };;
"Linux" ) statinode() { stat -c '%i' "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fdd9bd">[email protected]</a>"; return 0; };;
"Darwin" ) statinode() { stat -f '%i' "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="674327">[email protected]</a>"; return 0; };;
"FreeBSD" ) statinode() { stat -f '%i' "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3e1a7e">[email protected]</a>"; return 0; };;
* ) statinode() { ls -id "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="476307">[email protected]</a>" | cut -d ' ' -f 1; return 0; };;
esac
#export -f statinode
statinode / / / /
shopt -u nocasematch nullglob
)
Method 4
stat is part of the GNU Coreutils package. OSX uses a different stat implementation (presumably a BSD-based one) which doesn’t take the same command-line arguments.
You could always install GNU Coreutils on OSX. Of course that doesn’t help if you need a solution that works on OSX systems that don’t have GNU Coreutils.
Or, if I’m reading the OSX stat(1) man page correctly, stat -f %i file on OSX behaves like stat -c %i file using the Coreutils version. (Determining which version of stat you have is another matter; you could try stat --version >/dev/null; if it succeeds, you have the GNU Coreutils version.)
The ls -di solution is more portable and less trouble, but this is an alternative.
Method 5
Another solution:
#!/usr/bin/perl use strict; use warnings; die "Usage: $0 filenamen" if scalar @ARGV != 1; my $file = $ARGV[0]; my @stat = stat $file; die "$file: $!n" if not @stat; print "$stat[1]n";
You can probably safely assume that Perl is installed.
Method 6
Similar to jeff’s approach, stat could be tested directly as well.
(
if (stat -c '%i' / 1>/dev/null 2>&1; exit $?); then
statinode() { stat -c '%i' "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ac88ec">[email protected]</a>"; return 0; }
elif (stat -f '%i' / 1>/dev/null 2>&1; exit $?); then
statinode() { stat -f '%i' "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="466206">[email protected]</a>"; return 0; }
elif test -n "$(exec 2>/dev/null; ls -id / | cut -d ' ' -f 1)"; then
statinode() { ls -id "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d3f793">[email protected]</a>" | cut -d ' ' -f 1; return 0; }
else
echo 'Could not create statinode(). Exiting ...' && exit 1
fi
# export -f statinode
statinode / / / /
declare -f statinode
)
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0