递归复制文件夹,不包括某些文件夹

时间:2010-02-03 16:39:27

标签: bash unix shell scripting

我正在尝试编写一个简单的bash脚本,它将包含隐藏文件和文件夹的文件夹的全部内容复制到另一个文件夹中,但我想排除某些特定的文件夹。我怎么能做到这一点?

9 个答案:

答案 0 :(得分:307)

使用rsync:

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

请注意,使用sourcesource/是不同的。尾部斜杠表示将文件夹source的内容复制到destination。如果没有尾部斜杠,则表示将文件夹source复制到destination

或者,如果您要排除许多目录(或文件),则可以使用--exclude-from=FILE,其中FILE是包含要排除的文件或目录的文件的名称。

--exclude也可能包含通配符,例如--exclude=*/.svn*

答案 1 :(得分:36)

将tar与管道一起使用。

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

您甚至可以在ssh中使用此技术。

答案 2 :(得分:9)

您可以将find-prune选项一起使用。

来自man find的示例:

       cd /source-dir
       find . -name .snapshot -prune -o \( \! -name *~ -print0 \)|
       cpio -pmd0 /dest-dir

       This command copies the contents of /source-dir to /dest-dir, but omits
       files  and directories named .snapshot (and anything in them).  It also
       omits files or directories whose name ends in ~,  but  not  their  con‐
       tents.  The construct -prune -o \( ... -print0 \) is quite common.  The
       idea here is that the expression before -prune matches things which are
       to  be  pruned.  However, the -prune action itself returns true, so the
       following -o ensures that the right hand side  is  evaluated  only  for
       those  directories  which didn't get pruned (the contents of the pruned
       directories are not even visited, so their  contents  are  irrelevant).
       The  expression on the right hand side of the -o is in parentheses only
       for clarity.  It emphasises that the -print0 action  takes  place  only
       for  things  that  didn't  have  -prune  applied  to them.  Because the
       default `and' condition between tests binds more tightly than -o,  this
       is  the  default anyway, but the parentheses help to show what is going
       on.

答案 3 :(得分:2)

类似于Jeff的想法(未经测试):

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

答案 4 :(得分:2)

你可以使用tar,使用--exclude选项,然后在目标中解压缩它。例如

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

请参阅tar的手册页以获取更多信息

答案 5 :(得分: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

未经测试...

答案 6 :(得分:0)

受@ SteveLazaridis的回答启发,这将失败,这里是一个POSIX shell函数 - 只需复制并粘贴到你cpx中名为$PATH的文件中,并使其可执行(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"

答案 7 :(得分:0)

简单的解决方案(但我仍然更喜欢顶部评论中的 bash 模式匹配):

touch /path/to/target/.git
cp -n -ax * /path/to/target/
rm /path/to/target/.git

这利用了 -ncp 选项,强制 cp 不覆盖现有目标。

缺点:适用于 GNU cp。如果您没有 GNU cp,那么 cp 操作可能会返回错误代码 (1),这很烦人,因为您无法判断它是否是真正的失败.

答案 8 :(得分:-1)

?快速入门

运行:

rsync -av --exclude='path1/in/source' --exclude='path2/in/source' [source]/ [destination]

?笔记

  • -avr将创建一个名为[destination]的新目录。
  • sourcesource/创建不同的结果:
    • source-将源的内容复制到目的地。
    • source/-将文件夹源复制到目标位置。
  • 要排除许多文件:
    • --exclude-from=FILEFILE是包含要排除的其他文件或目录的文件的名称。
  • --exclude也可能包含通配符:
    • 例如--exclude=*/.svn*

修改自:https://stackoverflow.com/a/2194500/749232


?示例

开始文件夹结构:

.
├── destination
└── source
    ├── fileToCopy.rtf
    └── fileToExclude.rtf

运行:

rsync -av --exclude='fileToCopy.rtf' source/ destination

结尾文件夹结构:

.
├── destination
│   └── fileToExclude.rtf
└── source
    ├── fileToCopy.rtf
    └── fileToExclude.rtf