我有一个源目录,例如 /my/source/directory/ 和一个目标目录,例如 /my/dest/directory/,我想在一些限制下进行镜像。
- 我想将满足 find 命令某些条件的文件复制到目标目录,例如 -ctime -2 (少于 2 天)到 dest 目录以镜像
- 我想要的包括一些前缀,这样我就知道它来自哪里,例如 /source/directory
- 我想用绝对路径来完成所有这些,所以它不依赖于我从哪个目录运行
- 我猜没有 cd 命令也是很好的做法。
- 我希望创建子目录(如果它们不存在)
所以
/my/source/directory/1/foo.txt -> /my/dest/directory/source/directory/1/foo.txt
/my/source/directory/2/3/bar.txt -> /my/dest/directory/source/directory/2/3/bar.txt
我已经编写了以下命令行,但它看起来有点难看,有人可以做得更好吗?
find /my/source/directory -ctime -2 -type f -printf "%P\n" | xargs -IFILE rsync -avR /my/./source/directory/FILE /my/dest/directory/
如果您认为我应该自己添加此命令行作为答案,请发表评论,我不想贪图声誉。
I have a source directory eg /my/source/directory/ and a destination directory eg /my/dest/directory/, which I want to mirror with some constraints.
- I want to copy files which meet certain criteria of the find command, eg -ctime -2 (less than 2 days old) to the dest directory to mirror it
- I want to include some of the prefix so I know where it came from, eg /source/directory
- I'd like to do all this with absolute paths so it doesn't depend which directory I run from
- I'd guess not having cd commands is good practice too.
- I want the subdirectories created if they don't exist
So
/my/source/directory/1/foo.txt -> /my/dest/directory/source/directory/1/foo.txt
/my/source/directory/2/3/bar.txt -> /my/dest/directory/source/directory/2/3/bar.txt
I've hacked together the following command line but it seems a bit ugly, can anyone do better?
find /my/source/directory -ctime -2 -type f -printf "%P\n" | xargs -IFILE rsync -avR /my/./source/directory/FILE /my/dest/directory/
Please comment if you think I should add this command line as an answer myself, I didn't want to be greedy for reputation.
发布评论
评论(6)
这与(已关闭的)问题非常相似: Bash 脚本复制文件而不需要覆盖。 我给出的答案引用了 '
find | 其他答案中提到的 cpio
' 解决方案(减去时间标准,但这就是“相似”和“相同”之间的区别),并且还概述了使用 GNU“tar”的解决方案。ctime
当我在 Solaris 上测试时,GNU tar 和 (Solaris) cpio 都无法保留 ctime 设置; 确实,我不确定是否有办法做到这一点。 例如,touch 命令可以设置 atime 或 mtime 或两者 - 但不能设置 ctime。
utime()
系统调用也只采用 mtime 或 atime 值; 它不处理 ctime。 因此,我相信,如果您找到保留 ctime 的解决方案,该解决方案可能是特定于平台的。 (奇怪的例子:破解磁盘设备并编辑 inode 中的数据 - 不可移植,需要提升权限。)不过,重新阅读问题,我发现“保留 ctime”不是要求的一部分(唷); 它只是文件是否被复制的标准。我认为
'
cd
' 操作是必要的 - 但它们可以完全本地化到脚本或命令行,不过,如引用的问题和下面的命令行所示,其中第二个假定为 GNU tar。如果不使用
chdir()
(又名cd
),您需要专门的工具或选项来动态处理路径名的操作。带有空格、换行符等的名称
正如 Adam Hawes 所指出的,GNU 特定的“
find -print0
”和“xargs -0
”非常强大且有效。 有趣的是,GNU cpio 有一个选项来处理“find -print0
”的输出,即“--null
”或其缩写形式“-0
”。 因此,使用 GNUfind
和 GNUcpio
时,安全的命令是:注意:这不会覆盖备份目录下预先存在的文件。 为此,将
-u
添加到cpio
命令中。,GNU
tar
支持--null
(显然没有-0
短格式),并且也可以使用:类似地 带有空终止符的文件名非常聪明,也是一项有价值的创新(尽管我最近才意识到它,感谢 SO;它已经在 GNU tar 中存在至少十年了)。
This is remarkably similar to a (closed) question: Bash scripting copying files without overwriting. The answer I gave cites the '
find | cpio
' solution mentioned in other answers (minus the time criteria, but that's the difference between 'similar' and 'same'), and also outlines a solution using GNU 'tar'.ctime
When I tested on Solaris, neither GNU tar nor (Solaris) cpio was able to preserve the ctime setting; indeed, I'm not sure that there is any way to do that. For example, the
touch
command can set the atime or the mtime or both - but not the ctime. Theutime()
system call also only takes the mtime or atime values; it does not handle ctime. So, I believe that if you find a solution that preserves ctime, that solution is likely to be platform-specific. (Weird example: hack the disk device and edit the data in the inode - not portable, requires elevated privileges.) Rereading the question, though, I see that 'preserving ctime' is not part of the requirements (phew); it is simply the criterion for whether the file is copied or not.chdir
I think that the '
cd
' operations are necessary - but they can be wholly localized to the script or command line, though, as illustrated in the question cited and the command lines below, the second of which assumes GNU tar.Without using
chdir()
(akacd
), you need specialized tools or options to handle the manipulation of the pathnames on the fly.Names with blanks, newlines, etc
The GNU-specific '
find -print0
' and 'xargs -0
' are very powerful and effective, as noted by Adam Hawes. Funnily enough, GNUcpio
has an option to handle the output from 'find -print0
', and that is '--null
' or its short form '-0
'. So, using GNUfind
and GNUcpio
, the safe command is:Note:This does not overwrite pre-existing files under the backup directory. Add
-u
to thecpio
command for that.Similarly, GNU
tar
supports--null
(apparently with no-0
short-form), and could also be used:The GNU handling of file names with the null terminator is extremely clever and a valuable innovation (though I only became aware of it fairly recently, courtesy of SO; it has been in GNU tar for at least a decade).
您可以尝试使用复制传递模式 -p 进行 cpio。 我通常将它与覆盖所有(-u)、创建目录(-d)和维护修改时间(-m)一起使用。
请记住,find 应该生成相对路径名,这不符合您的绝对路径标准。 当然,这个问题可以使用 cd 来“解决”,您也不喜欢(为什么不呢?)
括号将生成一个子 shell,并将状态更改(即目录切换)保留在本地。 您还可以定义一个小过程来抽象出“丑陋”。
You could try cpio using the copy-pass mode, -p. I usually use it with overwrite all (-u), create directories (-d), and maintain modification time (-m).
Keep in mind that find should produce relative path names, which doesn't fit your absolute path criteria. This cold be of course be 'solved' using cd, which you also don't like (why not?)
The brackets will spawn a subshell, and will keep the state-change (i.e. the directory switch) local. You could also define a small procedure to abstract away the 'uglyness'.
如果您使用 find ,请始终使用 -print0 并通过 xargs -0 管道输出; 几乎总是如此。 如果您使用 find 的默认换行符输出,则名称中带有空格的第一个文件将使脚本停止运行。
我同意所有其他海报 - 如果可以的话,使用 cpio 或 tar。 它会做你想做的事并省去麻烦。
IF you're using find always use -print0 and pipe the output through xargs -0; well almost always. The first file with a space in its name will bork the script if you use the default newline terminator output of find.
I agree with all the other posters - use cpio or tar if you can. It'll do what you want and save the hassle.
另一种方法是使用 tar,
(cd $SOURCE; tar cf - .) | (cd $DESTINATION; tar xf -)
编辑:
啊,我错过了关于保留 CTIME 的部分。 我相信 tar 的大多数实现都会保留 mtime,但如果保留 ctime 很重要,那么 cpio 确实是唯一的方法。
另外,一些 tar 实现(GNU tar 就是其中之一)可以根据 atime 和 mtime 选择要包含的文件,尽管看起来不是 ctime。
An alternative is to use tar,
(cd $SOURCE; tar cf - .) | (cd $DESTINATION; tar xf -)
EDIT:
Ah, I missed the bit about preserving CTIME. I believe most implementations of tar will preserve mtime, but if preserving ctime is critical, then cpio is indeed the only way.
Also, some tar implementations (GNU tar being one) can select the files to include based on atime and mtime, though seemingly not ctime.
我想,由于您想包含“它来自哪里”,因此您将使用不同的源目录。 可以修改此脚本以将源目录作为参数,只需将 SRC=/my/source/directory 替换为 SRC=$1
编辑:删除冗余的 if 语句。
当文件名有空格时不起作用。
And I suppose, since you want to include "where it came from", that you are going to use different source directories. This script can be modified to take source dir as an argument simply by replacing SRC=/my/source/directory, with SRC=$1
EDIT: Removed redundant if statement.
Does not work when filenames have whitespaces.
!/usr/bin/sh
脚本复制具有相同目录结构的文件"
echo "请输入源目录的完整路径(以 / 开头并以 / 结尾):"
read spath
echo "请输入目标位置的完整路径(以 / 开头并以 / 结尾):"
读取 dpath
si=
echo "$spath" | awk -F/ '{print NF-1}'
for fname in
find $spath -type f -print
做
cdir=<代码>echo $fname | awk -F/ '{ for (i='$si'; i
如果 [ $cdir ]; 然后
如果 [ ! -d“$dpath$cdir”]; 然后
mkdir -p $dpath$cdir
菲
fi
cp $fname $dpath$cdir
完成
!/usr/bin/sh
script to copy files with same directory structure"
echo "Please enter Full Path of Source DIR (Starting with / and ending with /):"
read spath
echo " Please enter Full Path of Destination location (Starting with / and ending with /):"
read dpath
si=
echo "$spath" | awk -F/ '{print NF-1}'
for fname in
find $spath -type f -print
do
cdir=
echo $fname | awk -F/ '{ for (i='$si'; i<NF; i++) printf "%s/", $i; printf "\n"; }'
if [ $cdir ]; then
if [ ! -d "$dpath$cdir" ]; then
mkdir -p $dpath$cdir
fi
fi
cp $fname $dpath$cdir
done