セットアップスクリプトなどでmkdir,cp,chown,chgrp,chmodが頻発するときにシンプルに記述する方法
はじめに
アプリケーションのセットアップスクリプト や Dockerfile 、 Vagrantfile を記述しているときに、以下のようなコマンドが乱立することがあります。
mkdir
cp
chown
chgrp
chmod
mkdir
でコピー先のディレクトリを作成し、 cp
でファイルをコピー、 chown
/ chgrp
で所有者を変更し、 chmod
でパーミッションを変更、といった記述をしだすと、4コマンドは実行することになります。
これを1コマンドでやってしまおうというのが今回のエントリです。
検証環境
今回は非常に軽量なDcokerイメージである alpine
でも使えることを確認したいため、以下の環境を利用しました。
$ uname -moi
x86_64 unknown Linux
$ sh --help 2>&1 | head -n 1
BusyBox v1.30.1 (2019-06-12 17:51:55 UTC) multi-call binary.
ちなみに「Alpine Linux」は docker
コマンドが利用できれば簡単に起動できます。
$ docker run -i -t --rm alpine
4つのコマンドを1コマンドで実現するためのコマンド install
答えとしては非常に簡単で、 install
コマンドを利用します。
利用できるディストリビューション
いくつかのディストリビューションを確認しましたが、いずれもインストールされているようでした。
# CentOS
$ docker run -i -t --rm centos
[root@6742f69c602b /]# install --version | head -n 1
install (GNU coreutils) 8.22
# Ubuntu
$ docker run -i -t --rm ubuntu
root@854017b7cc5f:/# install --version | head -n 1
install (GNU coreutils) 8.28
# Debian
$ docker run -i -t --rm debian
root@4c81dcfa3f3f:/# install --version | head -n 1
install (GNU coreutils) 8.30
# Alpine
$ docker run -i -t --rm alpine
/# install 2>&1 | head -n 1
BusyBox v1.30.1 (2019-06-12 17:51:55 UTC) multi-call binary.
Macの場合は brew install gnutls
あたりでインストールできると思います。(僕の環境はすでにインストールされていた。)
使い方
ヘルプを確認してみます。
$ install --help
Usage: install [OPTION]... [-T] SOURCE DEST
or: install [OPTION]... SOURCE... DIRECTORY
or: install [OPTION]... -t DIRECTORY SOURCE...
or: install [OPTION]... -d DIRECTORY...
cp
コマンドとよく似ていて、 install コピー元ファイル コピー先ファイル
のように使います。
オプションも見ていきましょう。
今回利用するオプションのみに絞って表示させてみました。
-D create all leading components of DEST except the last,
or all components of --target-directory,
then copy SOURCE to DEST
-g, --group=GROUP set group ownership, instead of process' current group
-m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x
-o, --owner=OWNER set ownership (super-user only)
-p, --preserve-timestamps apply access/modification times of SOURCE files
to corresponding destination files
それぞれのオプションの役割を日本語で簡単に表現すると以下のようになります。
-D
:mkdir -p
と同じ。ディレクトリがない場合に作成する。-g
:chgrp
と同じ。グループを変更する。-m
:chmod
と同じ。パーミッションを変更する。-o
:chmod
と同じ。所有者を変更する。-p
:cp --preserve=timestamps
と同じ。タイムスタンプを保持する。
使用例
実際に利用してみます。
検証のために、コピー元ディレクトリ src/
と コピー先ディレクトリ dest/
を作成し、コピー元ディレクトリにコピーファイル hello.txt
を作成します。
以下のコマンドを見ていただければ、わかると思います。
$ mkdir -p src dest
$ echo hello > src/hello.txt
$ tree
.
├── src
│ └── hello.txt
└── dest
2 directories, 1 file
ここで、 src/hello.txt
を dest/
ディレクトリにコピーしたいと思います。
ただし、以下の条件を用意したいと思います。
- 所有者は
root
- グループは
guest
- パーミッションは
700
(所有者だけがアクセス可能) - コピー後のファイルパスは
dest/sub/world.txt
install
コマンドを使わない場合は以下のようになります。
# ディレクトリを作成
$ mkdir -p dest/test/
# コピー
$ cp --preserve=timestamps src/hello.txt dest/sub/world.txt
# 厳密に言うと、このあたりの処理でタイムスタンプが変わってしまうか?
# * ちなみに `chgrp` は `chmod` だけでも実現できます。
$ chmod root dest/sub/world.txt
$ chgrp guest dest/sub/world.txt
$ chmod 777 dest/sub/world.txt
install
コマンドを使う場合はワンライナーで実現できます。
$ install -o root -g guest -m 700 -D src/hello.txt dest/sub/world.txt
正しくコピーできたか確認してみます。
$ ls -l dest/
drwxr-xr-x 2 root guest 4096 Jan 21 01:22 sub
$ ls -l dest/sub
-rwx------ 1 root guest 6 Jan 21 01:22 world.txt
ひとこと
Dcokerfile
や Vagrantfile
が更にシンプルに書けるようになるはず。
次回作成時に使ってみたいと思います。
ディスカッション
コメント一覧
まだ、コメントがありません