Cara portabel untuk menemukan nomor inode

10

Pada awalnya saya menggunakan stat -c %i file(untuk membantu mendeteksi keberadaan penjara ), yang sepertinya berfungsi pada distribusi Linux di bawah matahari. Pada OS X 'saya harus menggunakan ls -i file | cut -d ' ' -f 1.

Apakah ada beberapa cara untuk menemukan nomor inode file dalam skrip shell yang portabel di platform * nix dan tidak bergantung pada hal-hal yang berubah-ubah ls?

l0b0
sumber
1
Anda mungkin tertarik, atau memiliki jawaban yang lebih baik untuk, Bagaimana saya tahu saya menjalankan chroot? .
Gilles 'SANGAT berhenti menjadi jahat'
Bisakah Anda menguraikan tentang "ls sangat terkenal"?
jlliagre
@ jlliagre: Yang lain sudah melakukannya dengan lebih baik.
l0b0
Oke, untuk file seperti itu, lihat balasan saya.
jlliagre

Jawaban:

11

Solusi yang mungkin: Spesifikasi POSIX untukls ditentukan -i, jadi mungkin itu portabel. Adakah yang tahu implementasi populer lsyang tidak mendukung ini, atau mencetaknya dengan cara yang berbeda dari contoh berikut:

$ ls -di /
2 /
l0b0
sumber
3
@jlliagre: Harap baca sebelum memposting. The statperintah tidak bekerja pada OS X, ls -dibekerja pada kedua.
l0b0
1
Bahkan Busybox lsmemiliki -ddan -isebagai fitur wajib (meskipun lsitu sendiri adalah opsional, seperti yang lainnya).
Gilles 'SO- stop being evil'
1
Kesalahpahaman Michael adalah persis apa yang saya komentari. Tidak layak komentar "baca sebelum memposting" yang cukup kasar dan tidak pantas.
jlliagre
2
Ada yang pengecualian untuk ini: lsdengan -ifront-bantalan dengan spasi pada setidaknya Solaris 10 (mungkin Solaris 11, saya belum diperiksa). Sepertinya ini adalah perilaku tradisional yang kembali ke Unix versi 7, jadi saya curiga banyak rasa korporat * nix menjaga perilaku ini (saya hanya punya Solaris 10 di tangan). Sedekat yang saya tahu, jika Anda menggunakan sesuatu yang dengan tepat menggambarkan bidang dalam spasi putih sewenang-wenang (jadi, tidak cut, tetapi misalnya awkatau hanya pemisahan bidang shell sendiri), mudah untuk mengharapkan string non-spasi putih pertama menjadi inode jumlah.
mtraceur
1
@ l0b0 Ya. Ini membutuhkan pengabdian masokis: sekelompok studi / pengujian dan menghafal untuk hasil yang terus berkurang. Itu mungkin, setidaknya untuk beberapa definisi "portabel", tetapi itu bukan pengalaman yang menyenangkan.
mtraceur
2

Ini harus portabel dan bekerja dengan nama file yang mengandung spasi, baris baru atau karakter aneh lainnya yang mengarah ke perilaku ls yang sangat berubah-ubah .

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

Untuk meningkatkan portabilitas, Anda juga dapat mengimplementasikan fungsi pembungkus khusus platform (di sini disebut statinode()) di sekitar statperintah yang dapat didasarkan pada output dari uname -s(lihat uname ).

ls akan dibutuhkan sebagai opsi mundur saja.

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

statadalah bagian dari paket GNU Coreutils . OSX menggunakan statimplementasi yang berbeda (mungkin berbasis BSD) yang tidak menggunakan argumen baris perintah yang sama.

Anda selalu dapat menginstal GNU Coreutils di OSX. Tentu saja itu tidak membantu jika Anda membutuhkan solusi yang berfungsi pada sistem OSX yang tidak memiliki GNU Coreutils.

Atau, jika saya membaca halaman manual stat OSX (1) dengan benar, stat -f %i fileOSX berperilaku seperti stat -c %i filemenggunakan versi Coreutils. (Menentukan versi yang statAnda miliki adalah masalah lain; Anda dapat mencoba stat --version >/dev/null; jika berhasil, Anda memiliki versi GNU Coreutils.)

The ls -disolusi adalah lebih portabel dan lebih sedikit kesulitan, tapi ini adalah sebuah alternatif.

Keith Thompson
sumber
0

Solusi lain:

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

Anda mungkin dapat dengan aman berasumsi bahwa Perl diinstal.

Keith Thompson
sumber
0

Mirip dengan pendekatan jeff, statbisa diuji langsung juga.

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