web-dev-qa-db-ja.com

Bashを使用して、あるディレクトリを別のディレクトリにマージするにはどうすればよいですか?

あるディレクトリから別のディレクトリにファイルをマージするシェルスクリプトを探しています。

サンプル:

html/
  a/
    b.html
  index.html

html_new/
  a/
    b2.html
    b.html

使用法:

./mergedirs.sh html html_new

結果:

html/
  a/
    b.html
    b2.html
  index.html

html/a/b.htmlhtml_new/a/b.htmlに置き換えられました
html/a/b2.htmlhtml_new/a/b2.htmlからコピーされました
html/index.htmlはそのまま維持されました

68
NVI

おそらくcp -R $1/* $2/だけが必要です—これは再帰的なコピーです。

(隠しファイル(名前がドットで始まるファイル)が存在する可能性がある場合、そのコマンドの前にshopt -s dotglob;を付けて、それらが一致することを確認する必要があります。)

76
Luke Maurer
cp -RT source/ destination/

source内のすべてのファイルとディレクトリはdestinationになります。たとえば、source/file1destination/file1にコピーされます。

-Tフラグは、代わりにsource/file1destination/source/file1にコピーされないようにします。

77
Flimm

Rsyncを見てみましょう

rsync --recursive html/ html_new/

Rsyncには設定するフラグがたくさんあるので、rsyncのマンページで詳細を確認してください

16
CarlG

Rsyncを使用するだけです。これは、リモートコピーに加えて、ローカルファイルのコピーとマージに最適なツールです。

rsync -av /path/to/source_folder/ /path/to/destination_folder/

Source_folderの内容のみを宛先にコピーするには、ソースフォルダーの末尾のスラッシュが必要であることに注意してください。そのままにしておくと、source_folder andの内容がコピーされます。これは、フォルダーをマージするため、おそらく探しているものではありません。

6
Gavster

cp -rは機能しませんか?

cp -r html_new/* html

または(最初のバージョンは「.something」ファイルをコピーしないため)

cd html_new; cp -r . ../html

コピーされたディレクトリ内のファイルのいずれかがパイプである場合、-rパイプからの読み取りであることに注意してください。それを避けるには、代わりに-Rを使用してください。

2
DVK
cd html
cp -r . /path/to/html_new
2
Brian Clapper

この質問とその受け入れられた答えは古くても、cpを使用する現在存在するものはエッジケースを処理しないか、対話的に作業する必要があるため、答えを追加しています。多くの場合、Edge-cases/scriptability/portability/multiple-sourcesは重要ではありません。その場合、単純さが優先され、認知負荷を減らすために、より少ないフラグでcpを直接使用することをお勧めします。 other times(または堅牢に再利用可能な関数の場合)この呼び出し/関数は有用であり、偶然にもbash固有ではありません(この質問はbashについてだったので、この場合は単なるボーナスです) 。一部のフラグは省略できます(たとえば、-a)。ただし、説明のために、すべてを明示的に長い形式(-Rを除く、以下を参照)に含めました。特定の機能がある場合は、フラグを削除するだけですdo n'tが必要です(または、非POS OSを使用している場合、またはcpのバージョンがそのフラグを処理しない場合-これをテストしました) GNU coreutils 8.25のcp):

mergedirs() {
    _retval=0
    _dest="$1"
    shift
    yes | \
        for _src do
            cp -R --no-dereference --preserve=all --force --one-file-system \
                  --no-target-directory "${_src}/" "$_dest" || { _retval=1; break; }
        done 2>/dev/null
    return $_retval
}

mergedirs destination source-1 [source-2 source-3 ...]

説明:

  • -Rこの回答 で説明されているように、一部のシステム(特にソースディレクトリの特殊ファイルに関して)で-r/--recursiveとは微妙に異なるセマンティクスを持ちます。
  • --no-dereference:SOURCEのシンボリックリンクをたどらない
  • --preserve=all:指定された属性(デフォルト:mode、ownership、timestamps)を保持し、可能であれば追加の属性:context、links、xattr、all
  • --force:既存の宛先ファイルを開けない場合は、それを削除して再試行します
  • --one-file-system:このファイルシステムにとどまる
  • --no-target-directory:DESTを通常のファイルとして扱います( この回答 で説明されています。つまり、If you do a recursive copy and the source is a directory, then cp -T copies the content of the source into the destination, rather than copying the source itself.
  • [yesからの入力をパイプ処理]:--forceでも、この特定の再帰モードでは、cpは各ファイルを上書きする前に要求するため、yesからの出力をパイプ処理することで非対話性を実現します
  • [/dev/null]への出力のパイピング:これは、cp: overwrite 'xx'?の行に沿って乱雑な質問文字列を黙らせるためです。
  • [return-val&early exit]:これにより、コピーが失敗するとすぐにループが終了し、エラーが発生した場合は1が返されます

ところで:

  • 私のシステムでこれと一緒に使用するファンキーな新しいフラグは、--reflink=autoで、いわゆる「ライトコピー」(コピーオンライト、ハードリンクと同じ速度の利点、同じサイズの利点)ファイルが将来どの程度発散するかに反比例するまで)。このフラグは最近のGNU cpで受け入れられ、最近のLinuxカーネル上の互換性のあるファイルシステムとの何もしない操作を実行します。他のシステム上のYMWV-a-lot。
2
Rowan Thorpe