一部のフォルダーを除き、フォルダーを再帰的にコピーする


197

非表示のファイルやフォルダーを含むフォルダーの内容全体を別のフォルダーにコピーする単純なbashスクリプトを作成しようとしていますが、特定の特定のフォルダーを除外します。どうすればこれを達成できますか?


1
findのようなものを想像します。-name *パイプでgrep / v "exclude-pattern"にパイプし、不要なものをフィルターにかけ、パイプでcpにコピーしてコピーを実行します。
i_am_jorf 2010

1
私はそのようなことをしようとしていましたが、パイプでcpを使用する方法を理解できませんでした
trobrock

1
これはおそらくスーパーユーザーに行くべきです。あなたが探しているコマンドはxargsです。パイプで接続された2つのタールのようなこともできます。
カイルバット

1
多分遅いとそれは質問に正確に答えませんが、ここにヒントがあります:ディレクトリの直接の子だけを除外したい場合、bashパターンマッチングを利用できますcp -R !(dir1|dir2) path/to/destination

1
!(dir1|dir2)パターンextglobをオンにする必要があることに注意してください(shopt -s extglobオンにするため)。
Boris D. Teoharov 2014

回答:


334

rsyncを使用します。

rsync -av --exclude='path1/to/exclude' --exclude='path2/to/exclude' source destination

sourcesource/は異なることに注意してください。末尾には、フォルダの内容をコピーするための手段スラッシュsourceにしますdestination。末尾にスラッシュがない場合は、フォルダsourceをにコピーすることを意味しますdestination

または、除外するディレクトリ(またはファイル)が多数ある場合は、を使用できます--exclude-from=FILEFILEは、除外するファイルまたはディレクトリを含むファイルの名前です。

--exclude 次のようなワイルドカードを含めることもできます --exclude=*/.svn*


10
コピーされるファイルを確認するために、-dry-runを追加することをお勧めします。
loretoparisi 2013

1
@AmokHuginnsson-どのシステムを使用していますか?Rsyncは、RHEL、CentOS、Debian、Ubuntuなど、私が知っているすべての主流のLinuxディストリビューションにデフォルトで含まれており、FreeBSDにも含まれていると思います。
Siliconrockstar 2015年

1
RHEL派生ディストリビューションの場合:yum install rsync、またはDebianベースのリリースの場合:apt-get install rsync。独自のハードウェアをベースにサーバーを構築しているのでない限り、これは問題ではありません。rsyncは、Amazon EC2ボックスと、ZeroLagとRackSpaceのボックスにデフォルトでインストールされています。
Siliconrockstar、2015

2
rsyncはcpに比べて非常に遅いようです。少なくともこれは私の経験でした。
Kojo

2
:gitのDIR無視する例えばrsync -av --exclude='.git/' ../old-repo/ .
nycynik

40

パイプと一緒にタールを使用してください。

cd /source_directory
tar cf - --exclude=dir_to_exclude . | (cd /destination && tar xvf - )

ssh全体でこの手法を使用することもできます。


このアプローチでは、まず不必要にターゲットソースをtarし(そしてアーカイブ内の特定のディレクトリを除外し)、次にターゲットでuntarします。推奨されません。
Wouter Donders 2016年

4
@Waldheriあなたは間違っている。これが最良の解決策です。これは、OPが要求したものを正確に実行し、ほとんどの* nixのようなOSのデフォルトインストールで機能します。風袋引きと解凍はファイルシステムのアーティファクト(メモリ内)なしでオンザフライで行われ、このtar + untarのコストはごくわずかです。
AmokHuginnsson

@WouterDonders Tarは最小限のオーバーヘッドです。圧縮は適用されません。
カイルバット

9

使用できます find-pruneオプション。

からの例 man find

       cd / source-dir
       見つける。-name .snapshot -prune -o \(\!-name *〜-print0 \)|
       cpio -pmd0 / dest-dir

       このコマンドは/ source-dirの内容を/ dest-dirにコピーしますが、省略します
       .snapshot(およびその中のすべて)という名前のファイルとディレクトリ。また
       名前が〜で終わるファイルまたはディレクトリを省略しますが、そのコン
       テント。構成-prune -o \(... -print0 \)は非常に一般的です。の
       ここでの考え方は、-pruneの前の表現が、
       剪定されます。ただし、-pruneアクション自体はtrueを返すため、
       -oを指定すると、右側のみが評価されます
       プルーニングされなかったディレクトリ(プルーニングの内容)
       ディレクトリは訪問さえされないので、その内容は関係ありません)。
       -oの右側の式は括弧内のみです
       明確にするために。-print0アクションが実行されるだけであることを強調します
       -pruneが適用されていないもののために。なぜなら
       テスト間のデフォルトの「and」条件は、-oよりも強く結合します。
       とにかくデフォルトですが、括弧は何が起こっているかを示すのに役立ちます
       オン。

マンページから直接関連性の高い例を見つけるための小道具。
David M

確かにいいですね!これは、オンラインドキュメントでも入手できます。残念ながらcpio、まだMSYS2用にパッケージ化されていません。
underscore_d

3

--excludeオプションを指定してtarを使用し、宛先でuntarできます。例えば

cd /source_directory
tar cvf test.tar --exclude=dir_to_exclude *
mv test.tar /destination 
cd /destination  
tar xvf test.tar

詳細はtarのmanページを参照してください


2

ジェフのアイデアに似ている(試されていない):

find . -name * -print0 | grep -v "exclude" | xargs -0 -I {} cp -a {} destination/

私はのサブディレクトリでこれを試してみました:それは確かにテストされていないし、簡単なテストで動作するようには思えないとき5人がこれをupvotedなぜ申し訳ありませんが、私は実際に取得しない/usr/share/iconsと、すぐに得find: paths must precede expression: 22x22、後者はその中のサブディレクトリのいずれかです。 。私のコマンドはfind . -name * -print0 | grep -v "scalable" | xargs -0 -I {} cp -a {} /z/test/(確かに、私はMSYS2を使用しているため、実際に/mingw64/share/icons/Adwaitaはですが、これがMSYS2の障害であることがわかりません)
underscore_d

0
EXCLUDE="foo bar blah jah"                                                                             
DEST=$1

for i in *
do
    for x in $EXCLUDE
    do  
        if [ $x != $i ]; then
            cp -a $i $DEST
        fi  
    done
done

未テスト...


これは誤りです。いくつかの問題:書かれているように、複数回除外されることが想定されていないファイル(除外されるアイテムの数、この場合は4)がコピーされます。除外リストの最初の項目である「foo」をコピーしようとしても、x = barに到達してもiがまだfooである場合はコピーされます。既存のツール(rsyncなど)なしでこれを実行する場合は、コピーを「for x in ...」ループの外のifステートメントに移動し、「for x ...」ループで論理ステートメントを変更しますif(true)コピーファイル。これにより、複数回のコピーができなくなります。
エリックブリングリー

0

失敗するSteveLazaridisの答え、@触発され、ここでPOSIXシェル機能である-ちょうどコピーして貼り付けるという名前のファイルにcpxYOUTで$PATH、それがexecutibleします(chmod a+x cpr)。[ソースは私のGitLabで維持されています

#!/bin/sh

# usage: cpx [-n|--dry-run] "from_path" "to_path" "newline_separated_exclude_list"
# limitations: only excludes from "from_path", not it's subdirectories

cpx() {
# run in subshell to avoid collisions
  (_CopyWithExclude "$@")
}

_CopyWithExclude() {
  case "$1" in
    -n|--dry-run) { DryRun='echo'; shift; } ;;
  esac

  from="$1"
  to="$2"
  exclude="$3"

  $DryRun mkdir -p "$to"

  if [ -z "$exclude" ]; then
      cp "$from" "$to"
      return
  fi

  ls -A1 "$from" \
    | while IFS= read -r f; do
        unset excluded
        if [ -n "$exclude" ]; then
          for x in $(printf "$exclude"); do
          if [ "$f" = "$x" ]; then
              excluded=1
              break
          fi
          done
        fi
        f="${f#$from/}"
        if [ -z "$excluded" ]; then
          $DryRun cp -R "$f" "$to"
        else
          [ -n "$DryRun" ] && echo "skip '$f'"
        fi
      done
}

# Do not execute if being sourced
[ "${0#*cpx}" != "$0" ] && cpx "$@"

使用例

EXCLUDE="
.git
my_secret_stuff
"
cpr "$HOME/my_stuff" "/media/usb" "$EXCLUDE"

誰かの答えが「失敗するだろう」と言って、何が悪いのか、どのように修正するのかを説明せずに言うのは役に立ちません...
underscore_d

@underscore_d:true、後から考えて、特に何が失敗したのか思い出せなくなった:-(
go2null

複数のもの:(1)ファイルを複数回コピーし、(2)ロジックは引き続き除外対象のファイルをコピーします。i = fooを使用してループを実行します。他のファイル(i = test.txtなど)の場合は、4回ではなく3回コピーされます。
エリックブリンリー

1
スティーブの答えの欠点を明確にしてくれた@EricBringleyに感謝します。(ただし、テストれてないと述べた)
go2null
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.