GNU Coreutilities を極める(1: 概要)

# GNU coreutils って何？ 
Linux(ディストリビューション不問)を新規ホストにインストールする際、たとえインストールオプションとしてミニマル(最低限)インストールを選んだとしても、絶対に必要となるパッケージが存在します。
それらは主に以下のような分類に属するソフトウェアとなります。

1. 電源投入直後、UEFI/BIOSから制御を引き継いで Linux カーネルを呼び出すためのプログラムである「ブートローダー」(systemd-boot,GRUB等)[^WSL1]
1. Linux カーネル(+カーネルモジュール)[^WSL2]
1. カーネルが最初に呼び出すプログラム(最近の主流は systemd,昔なら init)
1. libc (glibc 等) + 暗号化・認証等の基本ライブラリ群
1. スケジューラ(cron)や時刻同期(ntp)といった、基本的なバックグランドサービス関連ソフト
1. 昔ながらのシェルである sh の上位互換であるシェル(通常はbash)
1. root が /etc 配下の設定ファイルを直接編集する際に必要となる超軽量テキストエディタ(通常はviモードのvim,ディストリビューションによっては nano)
1. ユーザー/ネットワーク/デバイス/プロセスを管理するための root 向けコマンド類
1. シェルから呼び出す基本的なユーザーコマンド類

上記リストのうち、 4 以降の内容に関しては
「POSIXという規格上**必須**とされているコマンド群」の定義があるため、
ほとんどのディストリビューションは、ミニマルインストールであろうともこの規格を満たすようにパッケージをインストールする筈です(ただし、用途が古すぎて使われることがほぼないようなコマンドは除外されることが多い)。[^POSIXコマンド群]

[^WSL1]: Windows上で稼働する Linux である WSL に代表される、「稼働中のOSが別のLinuxカーネルを新規プロセスとして立ち上げるタイプ」の仮想ホストシステムでは不要。
[^WSL2]: WSLではこの部分が「Windowsが提供するサービス本体」となり、WSLサービスがバージョンアップされる、ということは Linux カーネルをバージョンアップすることと同じ意味となる。
[^POSIXコマンド群]: Linux/GNU が基本となった今となっては見る影もない、各種商用UNIXが雨後の筍のごとく乱立していた30年以上前の時代、「異なる商用UNIX間でも同じCライブラリとシェル用コマンドが使えなきゃダメ過ぎるだろ」という、開発者/ユーザー視点の要請から商用UNIXベンダーが制定した、「UNIX的OSが備えるべきライブラリインターフェースとシェル用コマンド群」規定が [POSIX規格](https://pubs.opengroup.org/onlinepubs/9699919799/ "本家のPOSIX規定")となる。

ここで、上記リストの末尾に「基本的なユーザーコマンド類」という項目がありますが、この分野のほとんどを含むパッケージ、それが coreutils,　正式名称は[GNU Core Utilities](https://www.gnu.org/software/coreutils/) となります[^busybox]。なお、正式名称をいちいち記述するのは面倒なので、以後、各種ディストリビューションでパッケージ名として採用されている coreutils 表記で統一します。

[^busybox]:もう一つ、同等の機能を持つパッケージとして　[BusyBox](https://busybox.net/) が存在しますが、こちらはシェルを含めた全コマンドが単一バイナリに格納されていて、主に組み込みLinuxで利用されるソフトウェアとなっています。

# それでは、具体的にどんなコマンドが coreutils に含まれているのか
シェル芸人とまではいわなくても、業務として他のマシンで稼働させるシェルスクリプトを書く必要がある人は、ミニマルインストールされたマシンでも使えるコマンドは何であるかを把握するために、

- どのコマンドがどのパッケージに入っているのか
- どのコマンドがシェルの内部関数/エイリアスなのか

をある程度知っておく必要があります。
そこで、現在私が利用している2つの環境で　coreutils　パッケージに含まれる実行可能ファイル名を調査してみまたいと思います。

なお、本記事を執筆している 2023年1月現在、GNU 本家における coreutils の最新バージョンは 9.1 となっておりますが、9.x は出てから日が浅いため、8.x　のバージョンを採用しているディストリビューションが多いはずです。

## Ubuntu LTS 22.04 の場合
私が普段使いしているマシンの　[Ubuntu](https://jp.ubuntu.com/) 22.04 LTS では　
```
hoge@fuga2(Ubuntu): dpkg -l | grep -i coreutils
ii  coreutils   8.32-4.1ubuntu1    amd64        GNU core utilities
hoge@fuga2(Ubuntu):
```
どうやら　8.x系の最新版である8.32 がインストールされているため、とりあえず 9.x ではなく　8.x に含まれるコマンド一覧を出力してみたいと思います(結果が長いので見たい人だけ、出力結果をどうぞ)。

<details><summary>Ubuntu LTS 22.04 出力結果</summary>

```
hoge@fuga2(Ubuntu): dpkg -L coreutils | grep 'bin/'
/bin/cat
/bin/chgrp
/bin/chmod
/bin/chown
/bin/cp
/bin/date
/bin/dd
/bin/df
/bin/dir
/bin/echo
/bin/false
/bin/ln
/bin/ls
/bin/mkdir
/bin/mknod
/bin/mktemp
/bin/mv
/bin/pwd
/bin/readlink
/bin/rm
/bin/rmdir
/bin/sleep
/bin/stty
/bin/sync
/bin/touch
/bin/true
/bin/uname
/bin/vdir
/usr/bin/[
/usr/bin/arch
/usr/bin/b2sum
/usr/bin/base32
/usr/bin/base64
/usr/bin/basename
/usr/bin/basenc
/usr/bin/chcon
/usr/bin/cksum
/usr/bin/comm
/usr/bin/csplit
/usr/bin/cut
/usr/bin/dircolors
/usr/bin/dirname
/usr/bin/du
/usr/bin/env
/usr/bin/expand
/usr/bin/expr
/usr/bin/factor
/usr/bin/fmt
/usr/bin/fold
/usr/bin/groups
/usr/bin/head
/usr/bin/hostid
/usr/bin/id
/usr/bin/install
/usr/bin/join
/usr/bin/link
/usr/bin/logname
/usr/bin/md5sum
/usr/bin/mkfifo
/usr/bin/nice
/usr/bin/nl
/usr/bin/nohup
/usr/bin/nproc
/usr/bin/numfmt
/usr/bin/od
/usr/bin/paste
/usr/bin/pathchk
/usr/bin/pinky
/usr/bin/pr
/usr/bin/printenv
/usr/bin/printf
/usr/bin/ptx
/usr/bin/realpath
/usr/bin/runcon
/usr/bin/seq
/usr/bin/sha1sum
/usr/bin/sha224sum
/usr/bin/sha256sum
/usr/bin/sha384sum
/usr/bin/sha512sum
/usr/bin/shred
/usr/bin/shuf
/usr/bin/sort
/usr/bin/split
/usr/bin/stat
/usr/bin/stdbuf
/usr/bin/sum
/usr/bin/tac
/usr/bin/tail
/usr/bin/tee
/usr/bin/test
/usr/bin/timeout
/usr/bin/tr
/usr/bin/truncate
/usr/bin/tsort
/usr/bin/tty
/usr/bin/unexpand
/usr/bin/uniq
/usr/bin/unlink
/usr/bin/users
/usr/bin/wc
/usr/bin/who
/usr/bin/whoami
/usr/bin/yes
/usr/sbin/chroot
/usr/bin/md5sum.textutils
hoge@fuga2(Ubuntu):
```
</details>

結果を見ると、Ubuntu は用途によって実行ファイルの保存先を

- /bin
- /usr/bin 
- /usr/sbin 

の3か所に振り分けていることがわかります。また、外部ライブラリを利用しない純粋な /usr/bin/md5sum コマンドと、textutils 外部ライブラリを利用するバージョンの　/usr/bin/md5sum.textutils コマンドが存在することもわかります。

総じて、Ubuntuはビルドする際に結構いじっている感じを受けます。

## ArchLinux の場合
続いて、ローリングアップデートで有名な [ArchLinux](https://www.archlinux.jp/) が稼働中の別マシンでも確認してみます。
```
hoge@fuga1(Arch): pacman -Q | grep -i coreutil
coreutils 9.1-3
hoge@fuga1(Arch): 
```
最新版が導入されていることがわかります。Ubuntu同様、こちらもパッケージに含まれる実行可能ファイルの一覧を取得します。

<details><summary>ArchLinux での出力結果</summary>

```
hoge@fuga1(Arch): pacman -Ql coreutils | grep 'bin/' | sed -e "s/.*\ //g"
/usr/bin/
/usr/bin/[
/usr/bin/b2sum
/usr/bin/base32
/usr/bin/base64
/usr/bin/basename
/usr/bin/basenc
/usr/bin/cat
/usr/bin/chcon
/usr/bin/chgrp
/usr/bin/chmod
/usr/bin/chown
/usr/bin/chroot
/usr/bin/cksum
/usr/bin/comm
/usr/bin/cp
/usr/bin/csplit
/usr/bin/cut
/usr/bin/date
/usr/bin/dd
/usr/bin/df
/usr/bin/dir
/usr/bin/dircolors
/usr/bin/dirname
/usr/bin/du
/usr/bin/echo
/usr/bin/env
/usr/bin/expand
/usr/bin/expr
/usr/bin/factor
/usr/bin/false
/usr/bin/fmt
/usr/bin/fold
/usr/bin/head
/usr/bin/hostid
/usr/bin/id
/usr/bin/install
/usr/bin/join
/usr/bin/link
/usr/bin/ln
/usr/bin/logname
/usr/bin/ls
/usr/bin/md5sum
/usr/bin/mkdir
/usr/bin/mkfifo
/usr/bin/mknod
/usr/bin/mktemp
/usr/bin/mv
/usr/bin/nice
/usr/bin/nl
/usr/bin/nohup
/usr/bin/nproc
/usr/bin/numfmt
/usr/bin/od
/usr/bin/paste
/usr/bin/pathchk
/usr/bin/pinky
/usr/bin/pr
/usr/bin/printenv
/usr/bin/printf
/usr/bin/ptx
/usr/bin/pwd
/usr/bin/readlink
/usr/bin/realpath
/usr/bin/rm
/usr/bin/rmdir
/usr/bin/runcon
/usr/bin/seq
/usr/bin/sha1sum
/usr/bin/sha224sum
/usr/bin/sha256sum
/usr/bin/sha384sum
/usr/bin/sha512sum
/usr/bin/shred
/usr/bin/shuf
/usr/bin/sleep
/usr/bin/sort
/usr/bin/split
/usr/bin/stat
/usr/bin/stdbuf
/usr/bin/stty
/usr/bin/sum
/usr/bin/sync
/usr/bin/tac
/usr/bin/tail
/usr/bin/tee
/usr/bin/test
/usr/bin/timeout
/usr/bin/touch
/usr/bin/tr
/usr/bin/true
/usr/bin/truncate
/usr/bin/tsort
/usr/bin/tty
/usr/bin/uname
/usr/bin/unexpand
/usr/bin/uniq
/usr/bin/unlink
/usr/bin/users
/usr/bin/vdir
/usr/bin/wc
/usr/bin/who
/usr/bin/whoami
/usr/bin/yes
hoge@fuga1(Arch):
```
</details>
出力結果を見ると、ArchLinux ではすべてのコマンドが　/usr/bin ディレクトリに格納され、このディレクトリ自体も coreutils パッケージが作っている模様です。
総じて、ローリングアップデートOSであるがゆえに、何も考えずにビルドしている感が凄いw

それはさておき、2つの環境でメジャーバージョンが異なる coreutils がインストールされていることが分かったので、8.x から 9.x にバージョンアップして追加されたコマンドは存在するのかを確認してみましょう。

## バージョンアップで追加されたコマンドは存在するのか？
ディストリビューションの差異によりコマンドの場所がまちまちなので、
先の出力結果のディレクトリ名部分を basename コマンドで除去、コマンド名でソートをかけ、NFSのホームディレクトリにリダイレクトして、diff を取ってみました。

```
hoge@fuga1(Arch):  for F in `pacman -Ql coreutils | grep 'bin/' | sed -e "s/.*\ //g" | grep -ve "bin/$"`; do basename $F; done | grep -ve "^$" | sort | uniq > coreutil9.1.arch.txt
```

```
hoge@fuga2(Ubuntu):  for F in `dpkg -L coreutils | grep 'bin/'`; do basename $F; done | grep -ve "^$" | sort | uniq > ~/coreutil8.32.ubuntu.txt
```

``` 
hoge@fuga: diff coreutil8.32.ubuntu.txt coreutil9.1.arch.txt
2d1
< arch
34d32
< groups
45d42
< md5sum.textutils
hoge@fuga:
```
結論から言えば、新しいコマンドは追加されていませんでした、というよりも最新版のArchLinux の方がコマンド数少ないしw

Ubuntu では md5sum コマンドが2種類あることは Ubuntu の出力説明で述べました。
そこで、md5sum 以外の2種類(arch と groups)がなぜ ArchLinux の coreutils パッケージで提供されていないのか調査してみると

- arch : `uname -a` コマンドで代用可能(Ubuntu上の man ページにもその旨が明記されている)なので省略された
- groups : ArchLinux は coreutils 版ではなく、シャドーパスワードを実装する shadow パッケージ版の groups コマンドを利用している

ということみたいです。
よくよく考えてみれば、「最低限の共通コマンド類を提供する」、というこのパッケージの性格上、新しいコマンドを追加、というバージョンアップはありえないわけで。

## 総括
Linux で　CLI を使う羽目になった初心者がまず最初に覚えるコマンド群である
- `cat`
- `chmod`
- `chown`
- `cp`
- `cut`
- `date`
- `head`
- `ln`
- `ls`
- `mkdir`
- `mv`
- `pwd`
- `rm`
- `rmdir`
- `tail`
- `touch`

全部このパッケージに含まれてます。
逆に、中級者以上の人がシェルスクリプト内やログイン後の通常業務で頻繁に利用するコマンド
- `grep`
- `sed`
- `awk`
- `bc`
- `diff`
- `make`
等は coreutils には含まれません[^mininstall]。
また、シェルスクリプト内で頻繁に利用する制御構文(if,case,function等)はシェルの内部機能であり、こちらも coreutils には含まれません。

[^mininstall]:ここで挙げたコマンド類は、coreutils には含まれていませんが、POSIXには規定されているため、ミニマルインストールでも別パッケージとしてインストールされます。

# まとめ
Linux 初心者をターゲットとした有料/無料の Linux コマンド講座って、実は　POSIX とか coreutils 講座であることが判明しました(苦笑)

また、自分では1回も使ったことのないコマンドの存在も明らかになったりして、非常に興味深かったです。
とりあえず、今回はここまでとし、[次回](https://qiita.com/p_cub/items/dedaf5ba9bb9b03f189a)は coreutils に含まれるコマンドの用途一覧(チートシート)を作成してみたいと思います。