我有一个目录结构,其中包含多个目录的多个.txt
文件。我想将所有这些.txt
文件复制到一个特定目录中。我在下面给出了我的目录结构:
Dir_1
a.txt
x.doc
b.txt
Dir_2
c.txt
Dir_3
d.txt
e.txt
y.doc
要将所有.txt
文件复制到目录中~/alltxt
,我使用以下cp
命令。
find . -name "*.txt" -exec cp {} ~/alltxt/ \;
它工作得很好。现在我的目录alltxt
如下所示。
alltxt
a.txt
b.txt
c.txt
d.txt
e.txt
但我发现我只想将更改的.txt
文件替换到该文件夹中。所以,我开始知道我可以使用rsync
如下命令来做到这一点。
find . -name '*.txt' -exec rsync -R {} ~/alltxt/ \;
但它会.txt
按文件夹复制文件,如下所示:
alltxt
Dir_1
a.txt
x.doc
b.txt
Dir_2
c.txt
Dir_3
d.txt
e.txt
y.doc
但是我怎样才能改变我的rsync
命令,使其像我的命令一样工作呢cp
?
答案1
rsync
有一个标志 ,--existing
它将避免复制目标上尚不存在的文件:
find . -type f -name '*.txt' -exec rsync --existing {} "$HOME/alltxt/" ';'
我还添加了-type f
确保find
只找到常规文件,并且我已从中删除了-R
标志 ( --relative
),rsync
因为我认为它在这种情况下没有用(使用此标志也是您获取目标上的子目录的原因)。我也使用$HOME
而不是~
因为我认为它看起来更好。
您可能还想在调用中添加-a
( --archive
)rsync
以保留所有权和修改时间等。
类似的方法,但使用cp
而不是rsync
:
find . -type f -name '*.txt' \
-exec sh -c 'for n; do d="$HOME/alltxt/${n##*/}"; [ -f "$d" ] && cp "$n" "$d"; done' sh {} +
这会找到所有.txt
文件并调用一个简短的 shell 脚本:
for n; do
d="$HOME/alltxt/${n##*/}"
[ -f "$d" ] && cp "$n" "$d"
done
该循环从 中获取许多.txt
文件find
。对于每个这样的名称n
,它会在 中创建目标文件路径d
,检查该路径是否引用现有的常规文件,如果是,则将给定文件复制到那里。
如果目标文件存在并且比找到的文件更旧,[ -f "$d" ]
您可以使用该测试而不是测试。[ "$d" -ot "$n" ]
这是一个非标准测试,但大多数 shell 都支持。
变量替换${n##*/}
将从 中的路径中删除目录n
,以便./some/path/file.txt
将其变为file.txt
(基本名称)。它可以被替换为$(basename "$n")
.
答案2
shopt -s globstar
cp --update --target-directory targetDirectory sourceRootDir/**/*.txt
在哪里:
shopt -s globstar
设置扩展的通配选项,其中包括**
模式--target-directory
或-t
给出要复制到的目标目录(也可以在所有参数的末尾指定,但将其放在脚本中通常更具可读性)。--update
或仅当目标较旧或不存在时才复制文件-u
。cp