cp -RTでディレクトリの中身だけ別のディレクトリにコピーする

先日、Railsチュートリアル用の環境をDockerで整えてみたが、そのときに詰まったのが「ゲスト環境で rails new して生成されたファイルを、ホスト環境との共有ボリュームにコピーする」ところ。ゲスト環境で /myapp (←自分のアプリ名)配下に生成されたファイルやディレクトリを、そのまま/appに移す必要があったのだが、普通に cp コマンドを使うだけではうまくいかなかった。

簡略化のため、以下のようなシンプルな例で考えてみる。 /src 配下のファイルやディレクトリを、すべて /dest 以下にコピーしたい。

tree -a
.
├── dest
└── src
    ├── .hidden
    ├── fuga.rb
    └── hoge
        └── hoge.rb

cp -R src dest だと、 src というディレクトリごとコピーされて、階層がひとつ深くなってしまう。

cp -R src dest
tree -a
.
├── dest
│   └── src
│       ├── .hidden
│       ├── fuga.rb
│       └── hoge
│           └── hoge.rb
└── src
    ├── .hidden
    ├── fuga.rb
    └── hoge
        └── hoge.rb

cp -R src/* dest は一見うまくいきそうだが、ドットファイル(この場合は .hidden)がコピーされない。

cp -R src/* dest
tree -a
.
├── dest
│   ├── fuga.rb
│   └── hoge
│       └── hoge.rb
└── src
    ├── .hidden
    ├── fuga.rb
    └── hoge
        └── hoge.rb

このような場合は、cpコマンドのTオプションを使う。通常のcpコマンドは、 cp src dest のような形式のとき、destがディレクトリなら cp src dest/src と同じ動作をする。しかしTオプションがある場合、最後の引数がディレクトリでもこのような特別扱いがなされないため、 cp -RT src dest とすれば、srcディレクトリの中身がdestディレクトリ内にコピーされる。

cp -RT src dest
tree -a
.
├── dest
│   ├── .hidden
│   ├── fuga.rb
│   └── hoge
│       └── hoge.rb
└── src
    ├── .hidden
    ├── fuga.rb
    └── hoge
        └── hoge.rb

これでドットファイルまで含めてコピーできた。

なお、Macにデフォルトで入っているcpコマンドはBSD版のため、 -T オプションがない。Macで使いたい場合は、 brew install coreutilsGNU版のcpコマンドをインストールする必要がある。

追記(1/12)

cp -r src/. dest/ でもドットファイルごとコピーできた。
また、docker-compose.ymlのvolumeに適切な指定をしていれば必要なファイルを自動で共有させられるので、ホスト/ゲスト間のやり取りはcpで頑張らない方が良さそう。

指摘いただいた@budougumi0617さん、ありがとうございます。