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

Dan*_*nny 6 find shell-script file-copy files

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

我已经说 30 dir 我有我需要使用上次修改日期查找命令输出找到的文件列表

a/a.txt
a/b/b.txt
a/www.txt
etc..
Run Code Online (Sandbox Code Playgroud)

例如,我希望创建文件夹“a”,并且只创建其中的 a.txt ……同样明智地创建另一个“a/b”并在其中创建 b.txt ……

ter*_*don 7

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

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

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


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

find /source -type d -exec mkdir -p {} /target
Run Code Online (Sandbox Code Playgroud)

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

while IFS= read -r file; do 
    cp /source/"$file" /target/"$file"
done
Run Code Online (Sandbox Code Playgroud)

更新

这个小脚本将移动 9 月 8 日之后修改的所有文件。它假定 GNU 版本findtouch. 假设您使用的是 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
Run Code Online (Sandbox Code Playgroud)

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


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

  1. 创建所有目录

     find ./ -type d -exec mkdir -p ../bar/{} \;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 查找并复制相关文件

     find ./ -type f -newer "$tmp" -exec cp {} /path/to/target/bar/{} \;
    
    Run Code Online (Sandbox Code Playgroud)
  3. 删除任何空目录

     find ../bar/ -type d -exec rmdir {} \;
    
    Run Code Online (Sandbox Code Playgroud)


Gil*_*il' 5

大伙儿

Pax是完成此任务的最佳工具。它是 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 {} +
Run Code Online (Sandbox Code Playgroud)

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

Zsh

使用glob 限定符 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
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用该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'
Run Code Online (Sandbox Code Playgroud)

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"
' {} \;
Run Code Online (Sandbox Code Playgroud)