はじめに
ふと、macOSでシンボリックリンクのリンク先の実体のファイルの情報をシンボリックリンクをしてして調べるコマンドがないかな?と思い立ち、いろいろと調べる中で分かったことをまとめました。
検証環境
以下の環境で確認しました。
- macOS : 15.5
- Homebrew : 4.5.8-150-g495b5be
- coreutils : stable 9.7
コマンドの所在を確認する
ここではHomebrewでインストールした誤入力矯正プログラムのslコマンドについて調べてみます。
シェルコマンドの所在を調べるコマンドにはwhichがあります。whichコマンドは引数に指定したコマンドが環境変数$PATHに保存されているコマンドサーチパス内に存在するかを順に調べ、存在したときのそのパスを返します。
slコマンドの所在を確認すると下記の実行結果から、/opt/homebrew/binであることが分かります。
$ which sl
/opt/homebrew/bin/sl
homebrewでインストールされたコマンドはこのディレクトリに実体へのシンボリックリンクが作成されます。
lsコマンドで調べる
whichコマンドの出力では実ファイルなのか、シンボリックリンクなのかが分かりません。そこでこのコマンドの出力をls -lコマンドの引数に指定してコマンドのリンク先を確認してみます。コマンドの実行結果を別のコマンドの引数として利用するには引数にしたいコマンドをバッククオート(`)で囲みます。
下記の実行結果からslコマンドのリンク先は 相対パスで../Cellar/sl/5.02/bin/slと示されます。シンボリックリンクのパス名と相対パスからslコマンドの絶対パスは/opt/homebrew/Cellar/sl/5.02/binであることが分かりますが表示はされません。また、パーミッションなどの情報はシンボリックリンクのもので実体のファイル情報は表示されません。
$ ls -l `which sl`
lrwxr-xr-x 1 sakabe admin 24 5 31 2023 /opt/homebrew/bin/sl -> ../Cellar/sl/5.02/bin/sl
実ファイルのパーミッションなどの情報はlsコマンドの-Lオプションを指定すると表示されます。
以下に実行結果を示します。コマンドパスはシンボリックリンクのままですがパーミッションなどの情報が実体のファイルの情報に変わります。-Tオプションを付けると日付に時間を含めて表示します。
$ ls -lL `which sl`
-r-xr-xr-x 1 sakabe admin 34975 6 16 2014 /opt/homebrew/bin/sl
$ ls -lLT `which sl`
-r-xr-xr-x 1 sakabe admin 34975 6 16 16:27:59 2014 /opt/homebrew/bin/sl
readlinkコマンドで調べる
lsコマンド以外でシンボリックリンクの実体を表示できるコマンドがないかと調べてみるとreadlinkコマンドがありました。オンライマニュアルを見るとstatコマンドととあわせて記載されています。
readlinkとstatの両コマンドについてlsコマンドで確認するとiノードが同じでリンク数が2なのでハードリンクであることが分かります。両コマンドはその所在やオンライマニュアルからmacOS標準コマンドであることも分かります。
$ ls -il `which stat readlink`
1152921500312523664 -rwxr-xr-x 2 root wheel 118768 5 4 14:39 /usr/bin/readlink
1152921500312523664 -rwxr-xr-x 2 root wheel 118768 5 4 14:39 /usr/bin/stat
オプションなしでreadlinkeコマンドを実行するとls -lコマンドの出力で表示されるシンボリックリンクの実体への相対パスが表示されました。もし、引数のファイルが実ファイルの場合は何も表示されません。
$ readlink `which sl`
../Cellar/sl/5.02/bin/sl
絶対パスを表示するには、-fオプションを指定します。このオプションを指定するとシンボリックリンクをたどった完全なパス(/opt/homebrew/Cellar/sl/5.02/bin/sl)が得られます。実行結果を以下に示します。
$ readlink -f `which sl`
/opt/homebrew/Cellar/sl/5.02/bin/sl
readlinkコマンドでは実体のファイルのパーミッションなどの情報が表示されないので上記のコマンド出力をlsコマンドの引数にして実行すればパーミッションなどの情報が表示されます。ただし、バッククオート(`)で囲まれた内側のバッククオートはエスケープ(\')しなければなりません。
$ ls -l `readlink -f \`which sl\``
-r-xr-xr-x 1 sakabe admin 34975 6 16 2014 /opt/homebrew/Cellar/sl/5.02/bin/sl
これでシンボリックリンクから実ファイルへの完全なパスがわかりました。
statコマンドで調べる
次にreadlinkと実体が同じstatコマンドを使ってシンボリックリンクの実体を調べてみます。
オプションを指定せずに実行した結果を以下に示します。statコマンドはls -lコマンドよりも詳細な情報を表示しているのがわかります。ただし、引数のシンボリックリンクの詳細情報になります。
$ stat `which sl`
16777234 20865533 lrwxr-xr-x 1 sakabe admin 0 24 "May 31 23:56:53 2023" "May 31 23:56:53 2023" "May 31 23:56:53 2023" "May 31 23:56:53 2023" 4096 0 0 /opt/homebrew/bin/sl
statコマンドの長い出力は次の表に示す15項目です。
| 出力位置 | 意味 | 出力 |
|---|---|---|
| 1 | デバイスID | 16777234 |
| 2 | inode | 20865533 |
| 3 | パーミッション + ファイル種別 | lrwxr-xr-x |
| 4 | ハードリンク数 | 1 |
| 5 | 所有者 | sakabe |
| 6 | 所有グループ | admin |
| 7 | 端末/デバイスの ID | 0 |
| 8 | ファイルサイズ(byte) | 24 |
| 9 | 最終アクセス時刻 | "May 31 23:56:53 2023" |
| 10 | 最終内容更新時刻 | "May 31 23:56:53 2023" |
| 11 | メタデータ変更時刻 | "May 31 23:56:53 2023" |
| 12 | 作成時刻 | "May 31 23:56:53 2023" |
| 13 | I/O 最適ブロックサイズ | 4096 |
| 14 | 512 byte ブロック数 | 0 |
| 15 | ファイルフラグ | 0 |
-Lオプションを指定するとシンボリックリンクの実体に関する情報が表示されます。
$ stat -L `which sl`
16777234 20865522 -r-xr-xr-x 1 sakabe admin 0 34975 "Jul 5 10:19:47 2025" "Jun 16 16:27:59 2014" "May 31 23:56:53 2023" "Jun 16 16:27:59 2014" 4096 72 0 /opt/homebrew/bin/sl
-xオプションを指定するとGNUのstatに類似した読みやすい形式で出力されます。シンボリックリンクにアクセスしているはずですが最終アクセスの日時(Access)は他の日時と同じままです。
$ stat -x `which sl`
File: "/opt/homebrew/bin/sl"
Size: 24 FileType: Symbolic Link
Mode: (0755/lrwxr-xr-x) Uid: ( 501/ sakabe) Gid: ( 80/ admin)
Device: 1,18 Inode: 20865533 Links: 1
Access: Wed May 31 23:56:53 2023
Modify: Wed May 31 23:56:53 2023
Change: Wed May 31 23:56:53 2023
Birth: Wed May 31 23:56:53 2023
さらにオプションにLを追加するとシンボリックリンクの実体のファイルに関する情報が表示されます。こちらの最終アクセス日時が正しく表示されているのが分かります。
$stat -xL `which sl`
File: "/opt/homebrew/bin/sl"
Size: 34975 FileType: Regular File
Mode: (0555/-r-xr-xr-x) Uid: ( 501/ sakabe) Gid: ( 80/ admin)
Device: 1,18 Inode: 20865522 Links: 1
Access: Sat Jul 5 10:19:47 2025
Modify: Mon Jun 16 16:27:59 2014
Change: Wed May 31 23:56:53 2023
Birth: Mon Jun 16 16:27:59 2014
readlinkコマンドの出力を利用した場合の出力を以下に示します。上記の実行結果とはファイルへのパスが異なるだけで、それ以外は同じです。
$ stat -x `readlink -f \`which sl\``
File: "/opt/homebrew/Cellar/sl/5.02/bin/sl"
Size: 34975 FileType: Regular File
Mode: (0555/-r-xr-xr-x) Uid: ( 501/ sakabe) Gid: ( 80/ admin)
Device: 1,18 Inode: 20865522 Links: 1
Access: Sat Jul 5 10:19:47 2025
Modify: Mon Jun 16 16:27:59 2014
Change: Wed May 31 23:56:53 2023
Birth: Mon Jun 16 16:27:59 2014
coreutilsのgreadlinkとgstatで調べる
HomebrewでGNUのcoreutilsをインストールしているとGNU版のgls、greadlink、gstatでもシンボリックリンクについて上記と同じように調べられます。以下にそれぞれの実行結果を示します。
greadlinkの出力をglsの引数にして実行した結果を以下に示します。
$ gls -l `greadlink -f \`which sl\``
-r-xr-xr-x 1 sakabe admin 34975 6 16 2014 /opt/homebrew/Cellar/sl/5.02/bin/sl
gstatコマンドの出力を以下に示します。オプションを指定しなくても見やすい表示になります。
$ gstat `which sl`
File: /opt/homebrew/bin/sl -> ../Cellar/sl/5.02/bin/sl
Size: 24 Blocks: 0 IO Block: 4096 symbolic link
Device: 1,18 Inode: 20865533 Links: 1
Access: (0755/lrwxr-xr-x) Uid: ( 501/ sakabe) Gid: ( 80/ admin)
Access: 2023-05-31 23:56:53.448585155 +0900
Modify: 2023-05-31 23:56:53.448585155 +0900
Change: 2023-05-31 23:56:53.448585155 +0900
Birth: 2023-05-31 23:56:53.448585155 +0900
greadlinkの出力をgstatの引数にして実行した結果を示します。ファイルパスが実ファイルへの完全なパスが表示されます。
$ gstat `greadlink -f \`which sl\``
File: /opt/homebrew/Cellar/sl/5.02/bin/sl
Size: 34975 Blocks: 72 IO Block: 4096 regular file
Device: 1,18 Inode: 20865522 Links: 1
Access: (0555/-r-xr-xr-x) Uid: ( 501/ sakabe) Gid: ( 80/ admin)
Access: 2025-07-05 10:19:47.781254532 +0900
Modify: 2014-06-16 16:27:59.000000000 +0900
Change: 2023-05-31 23:56:53.384444272 +0900
Birth: 2014-06-16 16:27:59.000000000 +0900
さいごに
シンボリックリンクにの実体ファイルの情報を確認できました。UNIX系OSには数多くのコマンドがあり、使ったことがないものが多いですね。また何か思いついたらコマンドを探してみようと思います。
