bash 递归复制文件夹,排除部分文件夹

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2193584/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 18:54:54  来源:igfitidea点击:

Copy folder recursively, excluding some folders

bashunixshellscripting

提问by trobrock

I am trying to write a simple bash script that will copy the entire contents of a folder including hidden files and folders into another folder, but I want to exclude certain specific folders. How could I achieve this?

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

回答by Kaleb Pederson

Use rsync:

使用 rsync:

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

Note that using sourceand source/are different. A trailing slash means to copy the contents of the folder sourceinto destination. Without the trailing slash, it means copy the folder sourceinto destination.

注意使用sourcesource/是不同的。尾部斜杠表示将文件夹的内容复制sourcedestination. 没有尾部斜杠,这意味着将文件夹复制sourcedestination.

Alternatively, if you have lots of directories (or files) to exclude, you can use --exclude-from=FILE, where FILEis the name of a file containing files or directories to exclude.

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

--excludemay also contain wildcards, such as --exclude=*/.svn*

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

回答by Kyle Butt

Use tar along with a pipe.

将 tar 与管道一起使用。

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

You can even use this technique across ssh.

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

回答by Paused until further notice.

You can use findwith the -pruneoption.

您可以使用find-prune选项。

An example from man find:

一个例子来自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.

回答by ghostdog74

you can use tar, with --exclude option , and then untar it in destination. eg

您可以使用带有 --exclude 选项的 tar,然后在目标中将其解压缩。例如

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

see the man page of tar for more info

有关更多信息,请参阅 tar 的手册页

回答by Matthew Flaschen

Similar to Jeff's idea (untested):

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

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

回答by Steve Lazaridis

EXCLUDE="foo bar blah jah"                                                                             
DEST=

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

Untested...

未经测试...

回答by go2null

inspired by @SteveLazaridis's answer, which would fail, here is a POSIX shell function - just copy and paste into a file named cpxin yout $PATHand make it executible (chmod a+x cpr). [Source is now maintained in my GitLab.

受到@SteveLazaridis 的回答的启发,这会失败,这是一个 POSIX shell 函数 - 只需复制并粘贴到一个以cpxyout命名的文件中$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 "" in
    -n|--dry-run) { DryRun='echo'; shift; } ;;
  esac

  from=""
  to=""
  exclude=""

  $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}" != "
EXCLUDE="
.git
my_secret_stuff
"
cpr "$HOME/my_stuff" "/media/usb" "$EXCLUDE"
" ] && cpx "$@"

Example usage

示例用法

##代码##