Coreutils

UNIX系のOS(POSIX互換を意識したOS)には必ずと言ってよいほどlsコマンドやcatコマンドといったコマンドが含まれている。こうしたコマンドはLinuxに限らずUNIX系のOSには必須のコマンドだ。

Linuxディストリビューションでは、特にこうした基本となるコマンドを「GNU Core Utilities (Coreutils)」というパッケージから取ってきていることが多い。それ以外のUNIX系OSでは、OSごとにCoreutilsのようなコマンドを持っている。それらのコマンドは、パッケージというよりもOSの一部という位置付けになっている。

Linuxではディストリビューションが異なっていても、lsコマンドやrmコマンドといった基本的なコマンドの動作は同じことが多い。使っているコマンドがGNU Core Utilitiesに含まれているコマンドであり、基本的に同じだからだ。一方、それ以外のUNIX系OSでは、OSごとに基本となるコマンドの動作はちょっとずつ違っている。同じパッケージを使っているわけではなく、OSごとに独自のコマンドを実装しているからだ。

「POSIX」という“お約束ごと”があるため、こうしたコマンドの基本的な動作はどのUNIX系OSでも同じことが多い。しかし、POSIXで規定されていない動作に互換性はなく、提供されている追加機能もOSごとに異なる。こうした事実を知らないまま、Linuxのときと同じ要領でMacのコマンドを使おうとすると困ったことが出てくる。

Mac

Macはカーネル環境に*BSD系技術を取り込んでいるほか、ユーザーランドのコマンドをFreeBSDなどから移植して使っている。詳しい説明は省くが、要するにユーザーから見た場合、Macに最初からインストールされているコマンドは、Coreutilsのコマンドとはちょっと動きが違うのだ。

この辺りの基本的なコマンドはPOSIXで動作が定められており、定められている部分に関しては多くのUNIX系OSで互換性がある。しかし、それらの動作は基本的なものであり、便利な機能はそれぞれのOSやCoreutilsで拡張されていて、互換性がない。

また、動作としては同じでも出力されるフォーマットが微妙に異なるとか、表示されるデータに違いがあるといったこともある。こうした挙動の違いを知らずに同じコマンドだと思って使っていくと思わぬところでハマることがある。最初からこうしたコマンドには「共通する部分」と「互換性のない部分」の2種類があることを知っておこう。

以下に、Coreutilsに含まれているコマンドから、Macのコマンドと動作が違う部分をいくつか取り上げて紹介する。

date

日付を出力したり設定したりするdateコマンドはよく使われるコマンドの一つだが、日付を進めたり、戻したりするオプションには互換性がない。例えば、Mac dateコマンドでは-vオプションで日時を進めたり戻したりすることができる。例えば、1週間前の日時を出力する場合は次のようになる。

Mac date

% date -v-1w
Tue Dec  7 10:25:47 JST 2021
%

このコマンドはCoreutilsのdateコマンドには存在しておらず、同じようなことをする場合には次のように--dateオプションを使うことになる。

Coreutils date

% date --date '1 week ago'
Tue Dec  7 10:25:58 JST 2021
% 

これらのオプションは拡張機能に分類されるものだが、便利なのでときどき使うのだ。しかし、OSごとに使い方が違うし、場合によってはこの機能は提供されていない。

df

dfコマンドはストレージの状態を出力するためのコマンドだが、OSごとに挙動が異なるコマンドでもある。大体の出力は似ているのだが、「Mac df」と「Linux df」では同じプラットフォームで実行しても次のように出力が異なっている。

Mac df

% df
Filesystem     512-blocks      Used  Available Capacity iused      ifree %iused  Mounted on
/dev/disk3s1s1 1942700360  30653304 1714903320     2%  575614 4293053646    0%   /
devfs                 403       403          0   100%     699          0  100%   /dev
/dev/disk3s6   1942700360        40 1714903320     1%       0 8574516600    0%   /System/Volumes/VM
/dev/disk3s2   1942700360    932056 1714903320     1%    1452 8574516600    0%   /System/Volumes/Preboot
/dev/disk3s4   1942700360      9512 1714903320     1%      52 8574516600    0%   /System/Volumes/Update
/dev/disk1s2      1024000     12328     986424     2%       3    4932120    0%   /System/Volumes/xarts
/dev/disk1s1      1024000     14568     986424     2%      30    4932120    0%   /System/Volumes/iSCPreboot
/dev/disk1s3      1024000       960     986424     1%      33    4932120    0%   /System/Volumes/Hardware
/dev/disk3s5   1942700360 194165984 1714903320    11%  628693 8574516600    0%   /System/Volumes/Data
map auto_home           0         0          0   100%       0          0  100%   /System/Volumes/Data/home
% 

Coreutils df

% df
Filesystem     1K-blocks      Used Available Use% Mounted on
/dev/disk3s1s1 971350180 113898520 857451660  12% /
/dev/disk3s6   971350180 113898520 857451660  12% /System/Volumes/VM
/dev/disk3s2   971350180 113898520 857451660  12% /System/Volumes/Preboot
/dev/disk3s4   971350180 113898520 857451660  12% /System/Volumes/Update
/dev/disk1s2      512000     18788    493212   4% /System/Volumes/xarts
/dev/disk1s1      512000     18788    493212   4% /System/Volumes/iSCPreboot
/dev/disk1s3      512000     18788    493212   4% /System/Volumes/Hardware
% 

カーネルやサブシステムに機能が強く依存するタイプのコマンドは、OSごとに挙動が異なる傾向が強い。dfはそうしたコマンドの一つだ。

ls

Linuxを使っていく上で絶対に外すことのできないコマンドがlsコマンドだ。しかし、このコマンドもOSの癖や拡張機能などによって挙動が異なりやすい。Macで「Mac ls」と「Coreutils ls」を実行すると、次のような違いが出る。

Mac ls

% ls -l
total 48
-rw-r--r--  1 daichi  staff  1346 Oct  3 14:39 LICENSE
-rw-r--r--  1 daichi  staff   238 Oct  3 14:39 Makefile
drwxr-xr-x  6 daichi  staff   192 Oct  3 14:39 data
-rw-r--r--  1 daichi  staff   432 Oct  3 14:39 main.c
-rw-r--r--  1 daichi  staff    74 Oct  3 14:39 main.h
-rw-r--r--  1 daichi  staff  2186 Oct  3 14:39 util_csv.c
-rw-r--r--  1 daichi  staff   449 Oct  3 14:39 util_file.c
% 

Coreutils ls

% ls -l
total 24
-rw-r--r-- 1 daichi staff 1346 Oct  3 14:39 LICENSE
-rw-r--r-- 1 daichi staff  238 Oct  3 14:39 Makefile
drwxr-xr-x 6 daichi staff  192 Oct  3 14:39 data
-rw-r--r-- 1 daichi staff  432 Oct  3 14:39 main.c
-rw-r--r-- 1 daichi staff   74 Oct  3 14:39 main.h
-rw-r--r-- 1 daichi staff 2186 Oct  3 14:39 util_csv.c
-rw-r--r-- 1 daichi staff  449 Oct  3 14:39 util_file.c
% 

「total」の出力や、出力フォーマットが多少異なっている。lsコマンドの出力結果を文字数ベースで切り取って操作するようなスクリプトを作って使っていたりすると、想定しているようには動いてくれなくなるわけだ。

stat

ファイルやディレクトリの詳細情報を得たい場合には、lsコマンドではなくstatコマンドを使った方が良いのだが、このコマンドも挙動がOSごとに異なりがちだ。MacとCoreutilsでは、それぞれ次のような挙動を見せる。

Mac stat

% stat .
16777234 7814491 drwxr-xr-x 11 daichi staff 0 352 "Oct  3 14:39:21 2021" "Oct  3 14:39:15 2021" "Oct  3 14:39:15 2021" "Oct  3 14:39:12 2021" 4096 0 0 .
% 

Coreutils stat

 % stat .
  File: .
  Size: 352             Blocks: 0          IO Block: 4096   directory
Device: 1,18    Inode: 7814491     Links: 11
Access: (0755/drwxr-xr-x)  Uid: (  501/  daichi)   Gid: (   20/   staff)
Access: 2021-10-03 14:39:21.280866865 +0900
Modify: 2021-10-03 14:39:15.684198006 +0900
Change: 2021-10-03 14:39:15.684198006 +0900
 Birth: 2021-10-03 14:39:12.283140329 +0900
 %

ファイルやディレクトリの情報、例えば作成日時や更新時刻などに基づいて処理を行うスクリプトを書きたいときがある。そんなときに便利なのがstatコマンドなのだが、このように動作がOSごとに異なる。Linux以外のOSでstatコマンドを使う場合には、そのOSのstatコマンドをよく調べて使う必要がある。

stty

ターミナルインタフェースとやりとりするためのsttyコマンドの動きも、OSごとに異なる傾向がある。次のような感じだ。

Mac stty

% stty
speed 9600 baud;
lflags: echoe echoke echoctl pendin
oflags: -oxtabs
cflags: cs8 -parenb
% 

Coreutils stty

% stty
speed 9600 baud;
ixany
-echok
% 

インタラクティブシェルやCUIエディタにおける入力、特にショートカットキー入力を調整するためのsttyコマンドを使うことがあるが、このコマンドもOSごとに動作が異なる傾向が見られる。

uname

システムの情報を出力させる最も基本的なコマンドの一つであるunameコマンドも、OSごとに挙動が変わりやすい。

Mac uname

% uname -a
Darwin Mac-mini-M1-2020.local 21.1.0 Darwin Kernel Version 21.1.0: Wed Oct 13 17:33:24 PDT 2021; root:xnu-8019.41.5~1/RELEASE_ARM64_T8101 arm64
%

Coreutils uname

% uname -a
Darwin Mac-mini-M1-2020.local 21.1.0 Darwin Kernel Version 21.1.0: Wed Oct 13 17:33:24 PDT 2021; root:xnu-8019.41.5~1/RELEASE_ARM64_T8101 arm64 arm64 Macmini9,1 Darwin
% 

unameはシェルスクリプトを作成する際に、プラットフォームごとに動作を切り分ける場合などの起点処理として使われることの多いコマンドなのだが、オプションなど使い方を誤るとLinux以外では適切に動作しないスクリプトが出来上がったりする。

uptime

システムの稼働時間を表示するuptimeコマンドは、MacもCoreutilsも基本的には同じ動作をするが、次のように出力のフォーマットが多少異なっている。

Mac uptime

% uptime
10:38  up 4 days, 15:13, 3 users, load averages: 2.01 1.84 1.75
% 

Coreutils uptime

% uptime
 10:38:15  up 4 days 15:12,  3 users,  load average: 2.01, 1.84, 1.75
%

文字数ベースでuptimeコマンドの出力を切り取って使うようなスクリプトを書いていると、こういった違いで処理が通らなくなる。

MacでCoreutilsを使うには

LinuxにCoreutilsをインストールできるように(そしてこれはデフォルトでインストールされていることがほとんどだ)、MacでもCoreutilsを使用することができる。Coreutilsを使いたければ、MacのコマンドではなくCoreutilsをインストールして使えばよい。

Coreutilsは前回取り上げたHomebrewを使ってインストールする。次のようにbrewコマンドを実行すればよい。

HomebrewでCoreutilsをインストール

brew install coreutils

Homebrew経由でインストールされたCoretutils系コマンドには「g」から始まる名前が付けられている。例えば、Coreutilsのlsコマンドは「gls」という名前で使えるようになっているし、catコマンドは「gcat」、rmコマンドは「grm」といった具合だ。

  • macOS Monterey - Coreutilsコマンド使用例

    macOS Monterey - Coreutilsコマンド使用例

Coreutilsのコマンドの場合、コマンド名の先頭に「g」を付けるというのは、Macに限らずほかのUNIX系OSでもしばしば行われている方法なので覚えておくと良いかもしれない。普段使っているOSがLinuxであり、Macは時々使う程度、という場合には、こんな感じでCoreutilsをインストールしてそちらのコマンドを使うようにしてしまえば、“ズレ”を感じる瞬間を減らすことができるだろう。

参考