シェルスクリプトでディレクトリ配下を検索した結果を、フォルダ階層を保ったまま別ディレクトリにコピーする
Contents
はじめに
タイトルがわかりにくいので、早速、具体的な例を上げて説明します。
EC-CUBEのソースコードを拝借し、 Tag
という文字を名前に含むファイルを、階層構造を保ったまま別のフォルダ ( /tmp/ec-cube
) にコピーしてみます。
検証環境
$ uname -moi
x86_64 MacBookPro10,1 Darwin
$ bash -version
GNU bash, バージョン 5.0.2(1)-release (x86_64-apple-darwin18.2.0)
Copyright (C) 2019 Free Software Foundation, Inc.
ライセンス GPLv3+: GNU GPL バージョン 3 またはそれ以降 <http://gnu.org/licenses/gpl.html>
準備
$ git clone https://github.com/EC-CUBE/ec-cube.git
$ ls -l
drwxrwx--- 40 genzouw staff 1280 2 20 22:43 ec-cube/
やりかた
Tag
という文字を名前に含むファイルは以下のコマンドで見つけられます。
# 一部のファイルだけに絞り込まれて出力されている
## -type f => ファイルのみを対象。ディレクトリは非対称。
## -name => Tagという文字を含むもののみを対象
$ find ec-cube -type f -name '*Tag*'
ec-cube/tests/Eccube/Tests/Web/Admin/Product/TagContorllerTest.php
ec-cube/tests/Eccube/Tests/DependencyInjection/Compiler/AutoConfigurationTagPassTest.php
ec-cube/src/Eccube/Form/Type/Admin/ProductTag.php
ec-cube/src/Eccube/Form/Type/Admin/TagType.php
ec-cube/src/Eccube/Repository/ProductTagRepository.php
ec-cube/src/Eccube/Repository/TagRepository.php
ec-cube/src/Eccube/Entity/ProductTag.php
ec-cube/src/Eccube/Entity/Tag.php
ec-cube/src/Eccube/Controller/Admin/Product/TagController.php
ec-cube/src/Eccube/DependencyInjection/Compiler/AutoConfigurationTagPass.php
これを階層構造を保ったまま /tmp/ec-cube
にコピーするには、 tar
コマンドを使います。
$ find ec-cube -type f -name '*Tag*' -print0 | tar --null -c --files-from=- -f - | (cd /tmp; tar xf -)
パット見わけがわからないが、なれます。(僕はなれはしないが、historyに残っているので流用しているw。)
コマンドの構成は、大きく2つの部分に別れています。
以下のように記述すると少しだけ見やすくなります。
$ (find ec-cube -type f -name '*Tag*' -print0 | tar --null -c --files-from=- -f -) \
| (cd /tmp; tar xf -)
- 1段目
find
で検索した結果を標準出力に流す。tar
コマンド は標準入力から対象ファイルを受け取り、圧縮。圧縮した結果を更に標準出力に流す。
- 2段目
- 展開対象のディレクトリに移動。
- 移動した先で標準入力から
tarball
データを受け取り、展開。
1段目 の find
コマンドのオプション -print0
と tar
コマンドの --null
は、今回のケースでは指定しなくても正常に動作します。
ファイル名やディレクトリ名にスペースが入っている場合にはこのオプションが必要です。find
の出力結果、 tar
の入力区切り文字としてデフォルトのスペースからヌル文字に変更してやる必要があります。
結果を確認してみる
# ディレクトリは新たにできている
$ cd /tmp/ec-cube/
# treeコマンドがあったので、構成を確認してみたところ確かにコピーされている
$ tree -f
.
├── ./src
│ └── ./src/Eccube
│ ├── ./src/Eccube/Controller
│ │ └── ./src/Eccube/Controller/Admin
│ │ └── ./src/Eccube/Controller/Admin/Product
│ │ └── ./src/Eccube/Controller/Admin/Product/TagController.php
│ ├── ./src/Eccube/DependencyInjection
│ │ └── ./src/Eccube/DependencyInjection/Compiler
│ │ └── ./src/Eccube/DependencyInjection/Compiler/AutoConfigurationTagPass.php
│ ├── ./src/Eccube/Entity
│ │ ├── ./src/Eccube/Entity/ProductTag.php
│ │ └── ./src/Eccube/Entity/Tag.php
│ ├── ./src/Eccube/Form
│ │ └── ./src/Eccube/Form/Type
│ │ └── ./src/Eccube/Form/Type/Admin
│ │ ├── ./src/Eccube/Form/Type/Admin/ProductTag.php
│ │ └── ./src/Eccube/Form/Type/Admin/TagType.php
│ └── ./src/Eccube/Repository
│ ├── ./src/Eccube/Repository/ProductTagRepository.php
│ └── ./src/Eccube/Repository/TagRepository.php
└── ./tests
└── ./tests/Eccube
└── ./tests/Eccube/Tests
├── ./tests/Eccube/Tests/DependencyInjection
│ └── ./tests/Eccube/Tests/DependencyInjection/Compiler
│ └── ./tests/Eccube/Tests/DependencyInjection/Compiler/AutoConfigurationTagPassTest.php
└── ./tests/Eccube/Tests/Web
└── ./tests/Eccube/Tests/Web/Admin
└── ./tests/Eccube/Tests/Web/Admin/Product
└── ./tests/Eccube/Tests/Web/Admin/Product/TagContorllerTest.php
20 directories, 10 files
応用編
find
コマンド実行箇所を変更すれば、別の条件で絞り込みを行うことが可能。
直近1日以内に変更が行われたものをコピー
$ find ec-cube -type f -mtime -1 -print0 | tar --null -c --files-from=- -f - | (cd /tmp; tar xf -)
ファイルサイズが100KB以上のものをコピー
$ find ec-cube -type f -size +100k -print0 | tar --null -c --files-from=- -f - | (cd /tmp; tar xf -)
Gitの変更履歴から直近2コミットで変更されたものをコピー
$ mkdir -p /tmp/ec-cube
$ cd ec-cube
$ git diff --name-only HEAD\^\^..HEAD | tar -c --files-from=- -f - | (cd /tmp/ec-cube; tar xf -)
ひとこと
一部のファイルだけを人に渡したりするときに便利。
ディスカッション
コメント一覧
まだ、コメントがありません