![克隆目录树结构并将文件复制到特定日期后修改的相应目录中](https://linux22.com/image/56002/%E5%85%8B%E9%9A%86%E7%9B%AE%E5%BD%95%E6%A0%91%E7%BB%93%E6%9E%84%E5%B9%B6%E5%B0%86%E6%96%87%E4%BB%B6%E5%A4%8D%E5%88%B6%E5%88%B0%E7%89%B9%E5%AE%9A%E6%97%A5%E6%9C%9F%E5%90%8E%E4%BF%AE%E6%94%B9%E7%9A%84%E7%9B%B8%E5%BA%94%E7%9B%AE%E5%BD%95%E4%B8%AD.png)
我有一个包含 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
,请更改source
为foo
和target
到bar
。
从你的问题中我无法判断你是否要复制全部目录,然后仅特定文件,或者如果您只想要包含文件的目录。上面的解决方案只会创建必要的目录。如果您想创建所有这些,请使用
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
,则必须每天计算正确的日期。
另一种方法是首先找到目录,在目标中创建它们,然后复制文件:
创造全部目录
find ./ -type d -exec mkdir -p ../bar/{} \;
找到并复制相关文件
find ./ -type f -newer "$tmp" -exec cp {} /path/to/target/bar/{} \;
删除所有空目录
find ../bar/ -type d -exec rmdir {} \;
答案2
帕克斯
帕克斯是完成这项任务的最佳工具。它是 POSIX 的cpio
and的替代品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
您可以使用find
withrsync
来执行此操作。
find ./source/ -newer /tmp/foo -print0 | rsync -av --files-from=- --from0 ./ ./destination/
测试
- 我创建了 2 个目录,名为来源和目的地。
出于测试目的,我创建了一个带有时间戳的临时文件,如下所示。
touch --date "2014-09-08" /tmp/foo
现在,里面来源目录中,我创建了一堆需要复制到的子目录目的地目录(一些子目录也带有空格,用于测试目的)。我还创建了一些示例文件。这 目的地目录当前为空。
我更改了子目录中其中一个文件的创建日期。
touch -c -t 1110111730 oldfile
现在,我
find
按照指定的方式执行命令。该find
命令根据我们指定的条件查找所有文件,然后管道获取我们的命令生成的rsync
文件列表 。find
现在,在目的地目录中,指定的文件oldfile
不应该在那里,因为它的时间早于我们想要的时间。
因此,我进入destination
目录进行检查,我得到了我想要的所有子目录结构,以及与我们的查找条件匹配的所有文件,并且指定的文件oldfile
不存在。
参考
答案4
这正是cpio
设计的使用方式。
find . -whatever -print | cpio -pvmd /path/to/copy/to/.
完毕。