如何在展平树结构的同时,bash复制目录/子目录中的所有文件(不包括列表中包含的文件)?

如何在展平树结构的同时,bash复制目录/子目录中的所有文件(不包括列表中包含的文件)?,bash,tree,find,copy,rsync,Bash,Tree,Find,Copy,Rsync,我有一个包含子目录和文件的目录(称为“源”)。使用bash,我需要将此目录及其每个子目录中的所有文件(仅文件,而不是目录)复制到不同的目录(称为“目的地”)。目录树不能维护/必须展平。只能复制文本文件(称为“excluded.txt”)中未包含的文件 源输入示例: /home/source/AAA/file1.xyz /home/source/AAA/GGG/file2.xyz /home/source/BBB/file3.tuv /home/source/BBB/HHH/file4.tuv

我有一个包含子目录和文件的目录(称为“源”)。使用bash,我需要将此目录及其每个子目录中的所有文件(仅文件,而不是目录)复制到不同的目录(称为“目的地”)。目录树不能维护/必须展平。只能复制文本文件(称为“excluded.txt”)中未包含的文件

源输入示例:

/home/source/AAA/file1.xyz 
/home/source/AAA/GGG/file2.xyz
/home/source/BBB/file3.tuv
/home/source/BBB/HHH/file4.tuv
/home/destination/file1.xyz
/home/destination/file2.xyz
/home/destination/file3.tuv
/home/destination/file4.tuv
目标输出示例:

/home/source/AAA/file1.xyz 
/home/source/AAA/GGG/file2.xyz
/home/source/BBB/file3.tuv
/home/source/BBB/HHH/file4.tuv
/home/destination/file1.xyz
/home/destination/file2.xyz
/home/destination/file3.tuv
/home/destination/file4.tuv
复制文件后,四个以上的文件名(file1.xyz等)将添加到excluded.txt(每个文件名位于新行)。然后,这些文件将定期从目标目录中删除

如果再次执行bash脚本,并且源文件存在,则如果它们的文件名出现在excluded.txt文件中,则不应将它们复制到目标


由于维护了目录树结构,我尝试使用“cp”和“rsync”失败。我使用“查找”也失败了,因为在执行复制操作之前,我无法对照“excluded.txt”列表检查结果。

find
应该是用于递归搜索的工具

find /home/source -type f $(printf "! -name %s" "$(cat exclude.txt)") -exec cp -n {} /home/destination \;
说明:

  • find/home/source
    :要搜索的根目录的路径。搜索是递归的
  • -键入f
    :仅检索文件
  • $(printf”!-name%s“$(cat exclude.txt))
    :将写入
    -名称文件1-名称文件2…
    ,列出要排除的所有文件
  • -exec cp-n{}/home/destination
    :为每个找到的项执行的操作<代码>{}表示找到的项

由@Aserre提供的答案有助于找到该解决方案。他的解决方案适用于所有不包含空格的文件。在阅读了(评估/执行字符串)和之后,我能够成功地编写和执行以下代码

while read -r line
do
    name="$line"
    exclude="$exclude ! -name \"$name\""
done < "/mnt/destination/exclude.txt"
cmd1="find \"/home/source\" -type f "
cmd2=" -exec cp -n {} \"/home/destination\" \;"
result=$cmd1$exclude$cmd2
eval $result
读取时-r行
做
name=“$line”
exclude=“$exclude!-name\“$name\”
完成
说明(计入@Aserre):

  • 读取时-r行
    :检查exclude.txt中的每一行。“-r”标志导致反斜杠被视为行的一部分
  • name=“$line”
    :excluded.txt中的整行存储在名为“name”的新字符串中
  • exclude=“$exclude!-name\“$name\”
    :将存储
    -名称为“file1”-名称为“file2”-名称…
    在名为“排除”的新字符串中。此字符串是要排除的所有文件的列表,每个文件前面都有
    -名称
    。每个引号前都需要反斜杠
  • cmd1=
    :将以下两个命令存储到名为“cmd1”的字符串中
  • find/home/source
    :要搜索的根目录的路径。搜索是递归的
  • -键入f
    :仅检索文件
  • -exec cp-n{}/home/destination
    :为每个找到的项执行的操作。{}表示找到的项
  • cmd2=
    :将上一个命令存储到名为“cmd2”的字符串中
  • result=$cmd1$exclude$cmd2
    :连接所有3个字符串
  • eval$result
    :获取名为“result”的字符串并将其作为命令运行

find/home/source/-type f-exec cp-n{}/home/destination/\;如果要避免覆盖目标文件夹中的现有文件,请使用“cp-n”@kuldeepsing我最初编写此代码段作为答案,但我忘了考虑OP有一个包含排除文件的文件。使用cp命令的-n选项可以避免重写文件。除非某个地方需要excluded.txtelse@KuldeepSingh感谢您提出的解决方案!如果文件仍保留在目标目录中,那么它就可以工作了。但是,由于文件会定期删除,因此excluded.txt列表会跟踪所有移动/复制的文件@Aserre@Aserre这很好用。具有排除列表可防止重复复制文件(因为它们会定期从目标位置删除)。多谢各位@因此,我刚刚确定此代码仅适用于不包含空格的文件名。如果文件名中有空格,如“file 2.txt”,则在执行代码时,会将文件重复复制到目标目录(如果原始副本已从目标目录中删除)。@a再次感谢您迄今为止的帮助。不幸的是,这并不能解决这个问题。如果源目录中有两个文件,“file1.txt”和“file2.txt”。来自
$(printf“!-name%s”“$(cat exclude.txt)”的新输出
命令显示
!-name file1.txt
,然后在下一行显示
“file 2.txt”
“file 2.txt”
应该与前面的
!-name
在同一行。我一直在论坛中搜索解决方案,似乎比我预期的要难。有什么想法吗?