克隆目录树结构并将文件复制到特定日期后修改的相应目录中

克隆目录树结构并将文件复制到特定日期后修改的相应目录中

我有一个包含 30 多个子目录的文件夹,我想获取在指定日期(比如 9 月 8 日,这是真实情况)之后修改的文件的列表,并使用相同的树结构进行复制,仅修改该文件夹中的文件

我说过 30 目录,我有使用上次修改日期 Find 命令输出找到的文件列表

a/a.txt
a/b/b.txt
a/www.txt
etc..

例如,我希望创建文件夹“a”,并且仅在其中包含a.txt...同样,对于其他文件夹,也将创建“a/b”并在其中包含b.txt...

答案1

假设您在文本文件中有所需的文件,您可以执行类似的操作

while IFS= read -r file; do 
    echo mkdir -p ${file%/*}; 
    cp /source/"$file" /target/${file%/*}/${file##*/}; 
done < files.txt 

这将读取列表的每一行,提取目录和文件名,创建目录并复制文件。您需要将source和更改target为您正在使用的实际父目录。例如,要复制/foo/a/a.txt/bar/a/a.txt,请更改sourcefootargetbar


从你的问题中我无法判断你是否要复制全部目录,然后仅特定文件,或者如果您只想要包含文件的目录。上面的解决方案只会创建必要的目录。如果您想创建所有这些,请使用

find /source -type d -exec mkdir -p {} /target

这将创建目录。一旦这些文件存在,只需复制文件:

while IFS= read -r file; do 
    cp /source/"$file" /target/"$file"
done

更新

这个小脚本将移动 9 月 8 日之后修改的所有文件。它假定 和 的 GNUfind版本touch。假设您使用的是 Linux,这就是您将拥有的。

#!/usr/bin/env bash    

## Create a file to compare against.
tmp=$(mktemp)
touch -d "September 8" "$tmp"

## Define the source and target parent directories
source=/path/to/source
target=/path/to/target

## move to the source directory
cd "$source"

## Find the files that were modified more recently than $tmp and copy them
find ./ -type f -newer "$tmp" -printf "%h %p\0" | 
    while IFS= read -rd '' path file; do
        mkdir -p "$target"/"$path"
        cp "$file" "$target"/"$path"
    done

严格来说,您不需要 tmp 文件。然而,这样一来,明天同样的脚本就可以工作了。否则,如果您使用 find's -mtime,则必须每天计算正确的日期。


另一种方法是首先找到目录,在目标中创建它们,然后复制文件:

  1. 创造全部目录

     find ./ -type d -exec mkdir -p ../bar/{} \;
    
  2. 找到并复制相关文件

     find ./ -type f -newer "$tmp" -exec cp {} /path/to/target/bar/{} \;
    
  3. 删除所有空目录

     find ../bar/ -type d -exec rmdir {} \;
    

答案2

帕克斯

帕克斯是完成这项任务的最佳工具。它是 POSIX 的cpioand的替代品tar(与tar它不同的是,它包括传递模式,而不仅仅是档案创建和提取)。遗憾的是,在某些 Linux 发行版的默认安装中省略了它,但它只是一个apt-get// yum/ emerge... 调用即可。

Pax 有一个限制:最近修改的目录将被复制,即使它们不包含要复制的文件。您可以随后删除空目录(除非您想要保留的目标中存在预先存在的空目录)。

cd /path/to/source
pax -rw -pp -T 201409080000 . /path/to/destination/
find /path/to/destination/ -depth -type d -exec rmdir {} +

我将提到其他可以适应pax没有过滤器的类似但不相同的用例的方法。

兹什

使用全局限定符 m按修改时间匹配文件(例如,m-10过去 10 天内修改的文件;您可以使用其他单位代替),并.匹配常规文件。这历史修改器 h保留文件名的目录部分。

cd /path/to/source
for x in **/*(.m-10); do
  mkdir -p -- $x:h
  cp -p -- $x /path/to/destination/$x
done

或者,您可以使用zmv函数用于复制与通配符表达式匹配的文件。没有内置方法来创建目标目录,因此我提供了一个函数来执行此操作。

autoload -U zmv
mkdir_cp () {
  mkdir -p -- ${(P)#}:h
  cp -- $@
}
cd /path/to/source
zmv -p mkdir_cp -Q '**/*(.m-10)' '/path/to/destination/$f'

POSIX 查找

通过find,您可以使用-mtime -10来匹配过去 10 天内修改的文件,或者-newer reference_time匹配 后修改的文件reference_files

touch -t 201409080000 /tmp/reference_time
cd /path/to/source
find . -type f -newer /tmp/reference_time -exec sh -c '
  mkdir -p /path/to/destination/"${0%/*}"
  cp "$0" "/path/to/destination/$0"
' {} \;

答案3

您可以使用findwithrsync来执行此操作。

find ./source/ -newer /tmp/foo -print0 | rsync -av --files-from=- --from0 ./ ./destination/ 

测试

  1. 我创建了 2 个目录,名为来源目的地
  2. 出于测试目的,我创建了一个带有时间戳的临时文件,如下所示。

    touch --date "2014-09-08" /tmp/foo
    
  3. 现在,里面来源目录中,我创建了一堆需要复制到的子目录目的地目录(一些子目录也带有空格,用于测试目的)。我还创建了一些示例文件。这 目的地目录当前为空。

  4. 我更改了子目录中其中一个文件的创建日期。

    touch -c -t 1110111730 oldfile
    
  5. 现在,我find按照指定的方式执行命令。该find 命令根据我们指定的条件查找所有文件,然后管道获取我们的命令生成的rsync文件列表 。find

现在,在目的地目录中,指定的文件oldfile不应该在那里,因为它的时间早于我们想要的时间。

因此,我进入destination目录进行检查,我得到了我想要的所有子目录结构,以及与我们的查找条件匹配的所有文件,并且指定的文件oldfile不存在。

参考

http://www.commandlinefu.com/commands/view/1481/rsync-find

答案4

这正是cpio设计的使用方式。

find . -whatever -print | cpio -pvmd /path/to/copy/to/.

完毕。

相关内容