こんにちは。構築業務を行っています下地です。
先日サーバをいじっている時、cp -a dirA/* dirBとやったらドットファイルがコピーされず、ちょっと手間どりました。
少し興味があり調べてみたので、今日はcpコマンドでドットファイルも含めてコピーする方法について書きます。
cpコマンドでディレクトリの中身をコピーする
まず、以下のようにdirAの内容をdirBにコピーしたい場合を考えてみましょう。
dirAにはドットファイルである.aaaと、通常ファイルであるbbb及びcccが入っています。
dirBは空です。
dirAとdirBの中身を同一にすることを目的とします。
[root@testserver ~]# ls -la dirA
total 4
drwxr-xr-x 2 root root 37 Oct 15 09:53 .
dr-xr-x---. 9 root root 4096 Oct 15 09:53 ..
-rw-r--r-- 1 root root 0 Oct 15 09:53 .aaa
-rw-r--r-- 1 root root 0 Oct 15 09:53 bbb
-rw-r--r-- 1 root root 0 Oct 15 09:53 ccc
[root@testserver ~]#
[root@testserver ~]# ls -la dirB
total 4
drwxr-xr-x 2 root root 6 Oct 15 09:55 .
dr-xr-x---. 9 root root 4096 Oct 15 09:53 ..
[root@testserver ~]#
[root@testserver ~]#
ではワイルドカードを使って中身をコピーしてみます。
[root@testserver ~]# cp -a dirA/* dirB
[root@testserver ~]# ls -la dirA
total 4
drwxr-xr-x 2 root root 37 Oct 15 09:53 .
dr-xr-x---. 9 root root 4096 Oct 15 09:53 ..
-rw-r--r-- 1 root root 0 Oct 15 09:53 .aaa
-rw-r--r-- 1 root root 0 Oct 15 09:53 bbb
-rw-r--r-- 1 root root 0 Oct 15 09:53 ccc
[root@testserver ~]# ls -la dirB
total 4
drwxr-xr-x 2 root root 26 Oct 15 10:24 .
dr-xr-x---. 9 root root 4096 Oct 15 09:53 ..
-rw-r--r-- 1 root root 0 Oct 15 09:53 bbb
-rw-r--r-- 1 root root 0 Oct 15 09:53 ccc
[root@testserver ~]#
このように、通常ファイルのbbbとcccはコピーできているのですが、ドットファイルの.aaaが移動先のdirBにはありません。
では以下の方法ではどうでしょうか?
ワイルドカードを使わずディレクトリ名だけで指定します。
[root@testserver ~]# cp -a dirA dirB
[root@testserver ~]# ls -la dirA
total 4
drwxr-xr-x 2 root root 37 Oct 15 09:53 .
dr-xr-x---. 9 root root 4096 Oct 15 09:53 ..
-rw-r--r-- 1 root root 0 Oct 15 09:53 .aaa
-rw-r--r-- 1 root root 0 Oct 15 09:53 bbb
-rw-r--r-- 1 root root 0 Oct 15 09:53 ccc
[root@testserver ~]# ls -la dirB
total 4
drwxr-xr-x 3 root root 17 Oct 15 10:28 .
dr-xr-x---. 9 root root 4096 Oct 15 09:53 ..
drwxr-xr-x 2 root root 37 Oct 15 09:53 dirA
[root@testserver ~]# ls -la dirB/dirA
total 0
drwxr-xr-x 2 root root 37 Oct 15 09:53 .
drwxr-xr-x 3 root root 17 Oct 15 10:28 ..
-rw-r--r-- 1 root root 0 Oct 15 09:53 .aaa
-rw-r--r-- 1 root root 0 Oct 15 09:53 bbb
-rw-r--r-- 1 root root 0 Oct 15 09:53 ccc
[root@testserver ~]#
次は.aaaも含む全てのファイルをコピーできました。
しかしdirBの直下にdirAがコピーされてしまい、入れ子構造になってしまいました。
どうにかdirAとdirBを同じ感じにコピーできないでしょうか。
方法1 カレントディレクトリを明示的に指定する
以下のように、cpコマンドのコピー元を「.」を使用してカレントディレクトリであることを明示します。
[root@testserver ~]# cp -a dirA/. dirB
[root@testserver ~]# ls -la dirA
total 4
drwxr-xr-x 2 root root 37 Oct 15 09:53 .
dr-xr-x---. 9 root root 4096 Oct 15 09:53 ..
-rw-r--r-- 1 root root 0 Oct 15 09:53 .aaa
-rw-r--r-- 1 root root 0 Oct 15 09:53 bbb
-rw-r--r-- 1 root root 0 Oct 15 09:53 ccc
[root@testserver ~]# ls -la dirB
total 4
drwxr-xr-x 2 root root 37 Oct 15 09:53 .
dr-xr-x---. 9 root root 4096 Oct 15 09:53 ..
-rw-r--r-- 1 root root 0 Oct 15 09:53 .aaa
-rw-r--r-- 1 root root 0 Oct 15 09:53 bbb
-rw-r--r-- 1 root root 0 Oct 15 09:53 ccc
[root@testserver ~]#
このようにドットファイルも含めてコピーされ、目的の形になりました。
方法2 Tオプションを利用する
cpコマンドは、コピー先にディレクトリを指定すると、それを特別に解釈します。
例えばカレントディレクトリに「aaa」というファイルと「dirA」というディレクトリがある場合、
cp aaa dirA
とコピー先にディレクトリを指定すると、
cp aaa dirA/aaa
と解釈され、結果としてaaaがdirAの直下にコピーされます。
Tオプションはこのような解釈をキャンセルします。
このオプションを使うと、先に実験してうまく行かなかった?「cp -a dirA dirB」が入れ子にならず使えます。
実際に試してみましょう。
[root@testserver ~]# cp -aT dirA dirB
[root@testserver ~]# ls -la dirA
total 4
drwxr-xr-x 2 root root 37 Oct 15 09:53 .
dr-xr-x---. 9 root root 4096 Oct 15 09:53 ..
-rw-r--r-- 1 root root 0 Oct 15 09:53 .aaa
-rw-r--r-- 1 root root 0 Oct 15 09:53 bbb
-rw-r--r-- 1 root root 0 Oct 15 09:53 ccc
[root@testserver ~]# ls -la dirB
total 4
drwxr-xr-x 2 root root 37 Oct 15 09:53 .
dr-xr-x---. 9 root root 4096 Oct 15 09:53 ..
-rw-r--r-- 1 root root 0 Oct 15 09:53 .aaa
-rw-r--r-- 1 root root 0 Oct 15 09:53 bbb
-rw-r--r-- 1 root root 0 Oct 15 09:53 ccc
[root@testserver ~]#
こんな感じでうまく行きました。
方法3 bashのオプションを変更する
通常、ワイルドカード指定(*)にはドットファイルが含まれません。
しかし、bashのオプションを変更することで、ワイルドカード指定にドットファイルも含めることができます。
そのオプションは「dotglob」というもので、shoptコマンドでON/OFFすることができます。
shopt -s dotglob →dotglobオプションを有効化
shopt -u dotglob →dotglobオプションを無効化
という感じです。これも試してみます。
[root@testserver ~]# shopt -s dotglob
[root@testserver ~]# cp -a dirA/* dirB
[root@testserver ~]# ls -la dirA
total 4
drwxr-xr-x 2 root root 37 Oct 15 09:53 .
dr-xr-x---. 9 root root 4096 Oct 15 09:53 ..
-rw-r--r-- 1 root root 0 Oct 15 09:53 .aaa
-rw-r--r-- 1 root root 0 Oct 15 09:53 bbb
-rw-r--r-- 1 root root 0 Oct 15 09:53 ccc
[root@testserver ~]# ls -la dirB
total 4
drwxr-xr-x 2 root root 37 Oct 15 11:06 .
dr-xr-x---. 9 root root 4096 Oct 15 09:53 ..
-rw-r--r-- 1 root root 0 Oct 15 09:53 .aaa
-rw-r--r-- 1 root root 0 Oct 15 09:53 bbb
-rw-r--r-- 1 root root 0 Oct 15 09:53 ccc
[root@testserver ~]# shopt -u dotglob
[root@testserver ~]#
このようにbashのオプションを変更することで、先ほどうまく行かなかったcp -a dirA/* dirBでもドットファイルを含めたコピーができました。
まとめ
ファイルをコピーする際は、単体コピーはもちろんディレクトリの中身を丸ごとコピーなどでcpコマンドを使うことが多いので、今回調べて勉強になりました。
またrsyncコマンドやmvコマンドなど、違う手法の方がやりやすい方もいるかもしれません。
自分ももっとコマンドに精通して適材適所で使えるようになりたいと思います。
お読み頂きありがとうございました。