RaspberryPiで理解する ls -l の表示内容

この図は私がよく使うコマンドを表しており,ダントツでlsコマンドの利用頻度が多いのがわかります.lsコマンドはディレクトリやファイルの一覧を表示するコマンドであり,Linuxを触る際は必ず触ります.

今回はls -lの表示内容についてRasPiを使って整理します.

はじめに

アクセス権を確認する際に複数のユーザが存在していると確認が捗るので,ここではpi2ユーザを新規作成します.

pi@raspi:~ $ sudo adduser pi2
Adding user pi2' ... Adding new grouppi2' (1001) …
Adding new user pi2' (1001) with grouppi2' …
Creating home directory /home/pi2' ... Copying files from/etc/skel' …
New password:
Retype new password:
passwd: password updated successfully
Changing the user information for pi2
Enter the new value, or press ENTER for the default
Full Name []:
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Is the information correct? [Y/n] y
pi@raspi:~ $ id pi2
uid=1001(pi2) gid=1001(pi2) groups=1001(pi2)
pi@raspi:~ $ sudo -u pi2 echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games

ちなみにデフォルトから若干変更があるかと思いますが,piユーザは以下のような状態となっています.PATHの内容は同じですが,所属グループはたくさん設定されています.

pi@raspi:~ $ id pi
uid=1000(pi) gid=1000(pi) groups=1000(pi),4(adm),20(dialout),24(cdrom),27(sudo),29(audio),44(video),46(plugdev),60(games),100(users),105(input),109(netdev),112(bluetooth),999(spi),998(i2c),997(gpio)
pi@raspi:~ $ sudo -u pi echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games

ls -l の表示内容

lsコマンドはファイルに関する様々な情報を表示することが出来ます.何が表示されているのか順に説明していきます.

pi@raspi:~ $ ls -l /home/
total 8
drwxr-xr-x 7 pi  pi  4096 Jul 15 13:00 pi
drwxr-xr-x 2 pi2 pi2 4096 Jul 15 13:05 pi2

total

ディレクトリ内のファイルに割り当てられたブロック単位のサイズの合計を表しています.-sオプションを使うと各ファイルに割り当てられたブロック単位のサイズを表示することができます.後から説明しますが,ここで表示されているサイズ4はディレクトリ自身のサイズです.

-s, –size print the allocated size of each file, in blocks

man ls
pi@raspi:~ $ ls -ls /home/
total 8
4 drwxr-xr-x 8 pi  pi  4096 Jul 15 13:00 pi
4 drwxr-xr-x 2 pi2 pi2 4096 Jul 15 13:05 pi2

① ファイルの種別

最初の1文字目でファイルの種別を表しています.代表的なものは以下の通りです.通常のファイル,ディレクトリ,シンボリックの3つくらいを知っていればはじめのうちは事欠きません.

表記種別
通常のファイル
bブロックデバイス(ブロックスペシャルファイル)
cキャラクタデバイス(キャラクタスペシャルファイル)
dディレクトリ
lシンボリックリンク
sソケットファイル

hostsとos-releaseを例にコマンドの結果を見てみましょう.それぞれ通常のファイルとシンボリックリンクであることがわかります.

pi@raspi:~ $ ls -l /etc/hosts /etc/os-release
-rw-r--r-- 1 root root 127 Jun  4 21:58 /etc/hosts
lrwxrwxrwx 1 root root  21 May 11 05:59 /etc/os-release -> ../usr/lib/os-release

② アクセス権 ④ 所有者とグループ

②と④については一緒に説明していきます.

まずはアクセス権.左から3文字毎に所有者のアクセス権グループのアクセス権その他のアクセス権の順で表示されています.それぞれの記号の意味は以下の通りです.この他にもいくつか特殊な権限がありますが,一旦置いておきます.

アクセス権はchmodコマンドで変更することが出来,3文字のアクセス権毎に3ビットと捉えて755や644といった数値(8進数)で表す場合があります.実際にはアクセス権は内部的に16ビットの整数で保持されています.

表記権限数値表記
r読み取り権4
w書き込み権2
x実行権1
権限なし0

続いて所有者とグループ.左から所有者所属グループを表しています.

piユーザでファイルを作成して,ip2ユーザから参照してみます.pi2ユーザはsample.txtの所有者ではなく,piグループにも所属していませんので,その他のアクセス権が適用されます.その他のアクセス権は読み取り権のみ設定されているため,pi2ユーザはcatコマンドで参照は出来ますが,ファイルの内容は変更出来ません.

pi@raspi:~ $ echo hoge > /tmp/sample.txt
pi@raspi:~ $ ls -l /tmp/sample.txt
-rw-r--r-- 1 pi pi 5 Jul 15 13:20 /tmp/sample.txt
pi@raspi:~ $ su pi2
pi2@raspi:~ $ cat /tmp/sample.txt
hoge
pi2@raspi:~ $ echo 'message from pi2' > /tmp/sample.txt
bash: /tmp/sample.txt: Permission denied

ちなみに/tmpディレクトリは全てのユーザが読み書きできる権限となっていますが,その他のアクセス権部分にスティッキービット(t)という特殊な権限が設定されています.この権限が設定されていると,所有者もしくはrootユーザしかファイルを削除できなくなります.

pi2@raspi:~ $ ls -ld /tmp/
drwxrwxrwt 8 root root 4096 Jul 15 13:35 /tmp/
pi2@raspi:~ $ rm /tmp/sample.txt
rm: remove write-protected regular file '/tmp/sample.txt'? y
rm: cannot remove '/tmp/sample.txt': Operation not permitted
pi@raspi:~ $ sudo usermod -a -G pi pi2
pi@raspi:~ $ id pi2
uid=1001(pi2) gid=1001(pi2) groups=1001(pi2),1000(pi)
pi@raspi:~ $ su pi2
pi2@raspi:~ $ rm /tmp/sample.txt
rm: remove write-protected regular file '/tmp/sample.txt'? y
rm: cannot remove '/tmp/sample.txt': Operation not permitted
pi2@raspi:~ $ exit
pi@raspi:~ $ sudo usermod -G pi2 pi2
pi@raspi:~ $ id pi2
uid=1001(pi2) gid=1001(pi2) groups=1001(pi2)

③ リンク数

対象が通常のファイルの場合,この数字はファイルのハードリンク数を表しています.

実際にファイルとそのハードリンクを作成してみます.Linux内部ではinodeを使ってファイルを管理していますが,同じinodeのファイルが2つありリンク数も2に増えていることがわかります.ここではシンボリックリンクも作成していますが,これはカウントされていません.

pi@raspi:~ $ echo 'num of links' > /tmp/sample.txt
pi@raspi:~ $ ls -l /tmp/sample.txt
-rw-r--r-- 1 pi pi 13 Jul 15 13:50 /tmp/sample.txt
pi@raspi:~ $ ln /tmp/sample.txt /tmp/sample_hlink.txt     # create hard link
pi@raspi:~ $ ln -s /tmp/sample.txt /tmp/sample_slink.txt  # create symbolic link
pi@raspi:~ $ ls -li /tmp/sample*
2965 -rw-r--r-- 2 pi pi 13 Jul 15 13:51 /tmp/sample_hlink.txt
2845 lrwxrwxrwx 1 pi pi 15 Jul 15 13:51 /tmp/sample_slink.txt -> /tmp/sample.txt
2965 -rw-r--r-- 2 pi pi 13 Jul 15 13:50 /tmp/sample.txt

ディレクトリの場合はハードリンクを作成出来ず,上記とは考え方が異なります.実際にディレクトリを作成して確認してみます.

新しく作成したディレクトリはリンク数部分が2となっています.ディレクトリの中身を-aオプションをつけて確認してみると,自身と親ディレクトリへのリンクがあることがわかります.これがリンク数2の正体です.

pi2@raspi:~ $ mkdir test-a test-b
pi2@raspi:~ $ ls -l
total 8
drwxr-xr-x 2 pi2 pi2 4096 Jul 15 14:00 test-a
drwxr-xr-x 2 pi2 pi2 4096 Jul 15 14:00 test-b
pi2@raspi:~ $ ls -la test-a/
total 8
drwxr-xr-x 2 pi2 pi2 4096 Jul 15 14:00 .    # itself
drwxr-xr-x 4 pi2 pi2 4096 Jul 15 14:00 ..   # parent directory

このディレクトリ内にファイルやディレクトリを配置してみます.ディレクトリ内にサブディレクトリを作成するとリンク数が増えましたが,ファイルを作成してもリンク数は変化ありません.つまりディレクトリにおけるリンク数とは,そのディレクトリに繋がるリンクの数を表しています.test-aディレクトリは,.(itself),..(parent),dir1,の3つに繋がっています.

pi2@raspi:~ $ mkdir test-a/dir1
pi2@raspi:~ $ ls -ld test-a/
drwxr-xr-x 3 pi2 pi2 4096 Jul 15 14:07 test-a
pi2@raspi:~ $ touch test-a/sample.txt
pi2@raspi:~ $ ls -ld test-a/
drwxr-xr-x 3 pi2 pi2 4096 Jul 15 14:08 test-a/
pi2@raspi:~ $ mkdir test-a/dir1/dir11
pi2@raspi:~ $ ls -ld test-a/
drwxr-xr-x 3 pi2 pi2 4096 Jul 15 14:08 test-a/
pi2@raspi:~ $ tree
.
├── test-a
│   ├── dir1
│   │   └── dir11
│   └── sample.txt
└── test-b
4 directories, 1 file

ちなみにシンボリックリンクはカウントされません.

pi2@raspi:~ $ ln -s dir1 test-a/dir1_symbolic
pi2@raspi:~ $ ls -ld test-a/
drwxr-xr-x 3 pi2 pi2 4096 Jul 15 14:15 test-a/
pi2@raspi:~ $ tree
.
├── test-a
│   ├── dir1
│   │   └── dir11
│   ├── dir1_symbolic -> dir1
│   └── sample.txt
└── test-b
5 directories, 1 file

⑤ サイズ

対象がファイルの場合は,バイト単位のサイズを表しています.

適当な文字を書き込んだファイルsample.txtに対してlsコマンドでサイズを確認してみると11Byteとなっています.

pi@raspi:~ $ echo 'size check' > sample.txt
pi@raspi:~ $ ls -l sample.txt
-rw-r--r-- 1 pi pi 11 Jul 15 14:25 sample.txt

ちなみにファイルシステム上では4096Byte単位でサイズを割り当てるので,11Byteのファイルであってもduコマンドでは4.0Kとして表示されます.

pi@raspi:~ $ sudo tune2fs -l /dev/mmcblk0p2 | grep 'Block size'
Block size: 4096
pi@raspi:~ $ du -h sample.txt
4.0K sample.txt

ディレクトリの場合も,ディレクトリ自身のサイズが表示されます.ここで注意したいのは,ディレクトリ自身のサイズというのはディレクトリの中身の合計サイズではありません.実際にディレクトリを作成して確認してみます.

作成したばかりのディレクトリのサイズが4096Byteとなっています.これがディレクトリ自身に割り当てられたサイズです.duコマンドの結果も4KByteとなっています.

pi@raspi:~ $ mkdir test
pi@raspi:~ $ ls -ld test/
drwxr-xr-x 2 pi pi 4096 Jul 15 14:52 test/
pi@raspi:~ $ stat test/
File: test/
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: b302h/45826d Inode: 134953 Links: 2
Access: (0755/drwxr-xr-x) Uid: ( 1000/ pi) Gid: ( 1000/ pi)
Access: 2020-07-15 14:52:22.589490689 +0900
Modify: 2020-07-15 14:52:22.589490689 +0900
Change: 2020-07-15 14:52:22.589490689 +0900
Birth: -
pi@raspi:~ $ du -h test/
4.0K test/

ファイルシステムは4096Byte単位なので,ディレクトリ内にそれより少し大きいファイルを作成してしてみます.6MByteのファイルを作成してサイズを確認すると,duコマンドの結果では6.1Mとサイズが大きくなっていますが,lsコマンドの結果では4096Byteのまま変化していないことがわかります.

pi@raspi:~ $ dd if=/dev/zero of=test/file_6M bs=1M count=6
6+0 records in
6+0 records out
6291456 bytes (6.3 MB, 6.0 MiB) copied, 0.054627 s, 115 MB/s
pi@raspi:~ $ ls -lh test/file_6M
-rw-r--r-- 1 pi pi 6.0M Jul 15 14:55 test/file_6M
pi@raspi:~ $ du -h test/
6.1M test/
pi@raspi:~ $ ls -ld test/
drwxr-xr-x 2 pi pi 4096 Jul 15 14:55 test/
pi@raspi:~ $ stat test/
File: test/
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: b302h/45826d Inode: 134953 Links: 2
Access: (0755/drwxr-xr-x) Uid: ( 1000/ pi) Gid: ( 1000/ pi)
Access: 2020-07-15 14:52:22.589490689 +0900
Modify: 2020-07-15 14:55:32.813492930 +0900
Change: 2020-07-15 14:55:32.813492930 +0900
Birth: -

ちなみにstatコマンドで表示されているBlocksは8となっていますが,これは512Byte単位でカウントされています.どんどん話がそれてしまいそうなのでこのくらいにしておきます...

⑥ タイムスタンプ

タイムスタンプはいくつかの種類がありますが,ls -lで表示されるものはmtimeです.これらのタイムスタンプはstatコマンドでも確認出来ます.

タイムスタンプの種類説明確認コマンド
atimeaccsess time
ファイルまたはディレクトリのデータが最後にアクセスされた時刻
ls -lu
ctimechange time
inodeのステータスが最後に変更された時刻
ls -lc
mtimemodify time
ファイルまたはディレクトリのデータが最後に修正された時刻
ls -l

実際にファイルを作成して,これらのタイムスタンプがどのように更新されるのか確認します.

pi2@raspi:~ $ echo 'time stamp check' > sample.txt
pi2@raspi:~ $ stat sample.txt
File: sample.txt
Size: 17 Blocks: 8 IO Block: 4096 regular file
Device: b302h/45826d Inode: 133348 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1001/ pi2) Gid: ( 1001/ pi2)
Access: 2020-07-15 15:56:09.056259375 +0900
Modify: 2020-07-15 15:56:09.056259375 +0900
Change: 2020-07-15 15:56:09.056259375 +0900
Birth: -

atimeは最後にアクセスした時刻を表します.OSやプログラムが動作する際には様々なファイルへアクセスを行いますが,その都度atimeを更新しているとパフォーマンスが低下します.したがってatimeの更新は,ファイルシステムのマウント時にnoatimeオプションで無効化するか,relatime(relative atime)オプションで更新頻度を下げたほうが良いです.relatimeは前回のatimeがmtimeまたはctimeより古い場合にatimeを更新します.

atimeを更新するのにcatコマンドでファイルを参照する例がありますが,RasPiではルートファイルシステムにnoatimeオプションをつけてマウントしているためこの方法では変更出来ません.atimeオプションが付いていないファイルシステムで確認するか,touchコマンドで直接atimeを更新してしまうことは出来ます.manではtouchコマンドの-aオプションの説明は “change only the access time” となっていますが,inode内の属性値であるmtimeが更新されたのでctimeも更新されています.

pi2@raspi:~ $ mount | grep /dev/mmcblk0p2
/dev/mmcblk0p2 on / type ext4 (rw,noatime)
pi2@raspi:~ $ touch -a sample.txt
pi2@raspi:~ $ stat sample.txt
File: sample.txt
Size: 17 Blocks: 8 IO Block: 4096 regular file
Device: b302h/45826d Inode: 133348 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1001/ pi2) Gid: ( 1001/ pi2)
Access: 2020-07-15 15:58:37.543468714 +0900
Modify: 2020-07-15 15:56:09.056259375 +0900
Change: 2020-07-15 15:58:37.543468714 +0900
Birth: -

mtimeはファイルやディレクトリを修正した際に更新されます.ファイルに文字列を追記してみるとmtimeが更新されていることがわかります.atimeと同様にここでもctimeが更新されています.

pi2@raspi:~ $ echo 'add message' >> sample.txt
pi2@raspi:~ $ stat sample.txt
File: sample.txt
Size: 29 Blocks: 8 IO Block: 4096 regular file
Device: b302h/45826d Inode: 133348 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1001/ pi2) Gid: ( 1001/ pi2)
Access: 2020-07-15 16:28:37.543468714 +0900
Modify: 2020-07-15 16:44:59.162220964 +0900
Change: 2020-07-15 16:44:59.162220964 +0900
Birth: -

⑦ ファイルやディレクトリの名前

これは説明するまでもなくファイルやディレクトリの名前です.

シンボリックリンクの場合はリンク先も表示されます.

おわりに

ls -lの出力内容を整理しました.

全部知っていましたか?

コメント

タイトルとURLをコピーしました