我试图写一个简单的bash脚本,将复制一个文件夹的全部内容,包括隐藏的文件和文件夹到另一个文件夹,但我想排除某些特定的文件夹。我怎么才能做到呢?


当前回答

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

未经考验的……

其他回答

使用焦油和管道。

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

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

使用 rsync:

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

注意,使用source和source/是不同的。后面的斜杠表示将文件夹源的内容复制到目标。如果没有后面的斜杠,它意味着将文件夹源复制到目标。

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

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

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

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

find . -name * -print0 | grep -v "exclude" | xargs -0 -I {} cp -a {} destination/
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

未经考验的……