我需要复制 /parent 下的所有文件夹(到新位置),但前提是它有 123.dat - 在这种情况下,我也需要复制该文件夹,但不需要复制其中包含的任何其他文件。
因此:
|parent
| |a
| | 123.dat
| | 456.dat
| |b
| | 123.dat
| | 789.dat
| |c
| | 456.dat
| | 789.dat
变成:
|parent
| |a
| | 123.dat
| |b
| | 123.dat
我如何在 Linux 中做到这一点?这个领域不是我的专长,到目前为止,我尝试搜索类似的东西都没有成功。
答案1
文件/文件夹结构:
$ find src | sort
src
src/a
src/a/123.dat
src/a/456.dat
src/b
src/b/123.dat
src/b/768.dat
src/c
src/c/456.dat
src/c/768.dat
复制匹配的文件,保留相对路径(浅,不超过 1 个文件夹):
命令:
$ (cd src && cp -v --parents -- */123.dat ../dest)
输出:
a -> ../dest/a
'a/123.dat' -> '../dest/a/123.dat'
b -> ../dest/b
'b/123.dat' -> '../dest/b/123.dat'
- 我使用了 和 的子 shell
(
,)
以便使用 时不更改原始工作目录cd
。我必须src
在执行之前输入cp
,以便不是在 中创建src/
为基本目录dest
。 - 无法处理文件数量超过 bash 参数限制的情况(如果我没记错的话,通常在 65k 左右)
替代方法(使用find
可调深度限制):
命令:
$ (cd src && find . -maxdepth 2 -type f -name '123.dat' -exec cp -v -t "../dest" --parents {} +)
输出:
./b -> ../dest/./b
'./b/123.dat' -> '../dest/./b/123.dat'
./a -> ../dest/./a
'./a/123.dat' -> '../dest/./a/123.dat'
笔记:
- 我使用了 和 的子 shell
(
,)
以便使用 时不更改原始工作目录cd
。我必须src
在执行之前输入find
,以便不是在 中创建src/
为基本目录dest
。 - 我指定
-type f
确保只123.dat
考虑具有名称的文件,而不是碰巧具有该名称的目录
替代方法(使用rsync
,不受深度限制):
命令:
$ rsync -rv --include=123.dat --include='*/' --exclude='*' --prune-empty-dirs src/ dest
输出:
building file list ... done
created directory dest
./
a/
a/123.dat
b/
b/123.dat
sent 205 bytes received 90 bytes 590.00 bytes/sec
total size is 0 speedup is 0.00
再检查一遍:
$ find dest
dest
dest/b
dest/b/123.dat
dest/a
dest/a/123.dat
笔记:
- 结尾
/
是src/
故意的,这样只复制文件夹的内容,而不是文件夹本身。 --exclude='*'
默认排除所有内容--include='*/
覆盖排除并包含所有文件夹--include='123.dat'
覆盖排除并包含名为“123.dat”的文件(和文件夹)--prune-empty-dirs
确保没有创建空文件夹(例如c
)
答案2
一种方法是在新位置创建父目录的新版本,然后如果子目录包含 123.dat,则复制到子目录中。这使用 Bash shell 的通配符功能来查找子目录,因此仅适用于紧邻父目录下的目录。在示例中,我假设父目录位于名为的目录中/location1/
,并将移动到/location2/
:
mkdir -p /location2/parent
for d in /location1/parent/*
do if [[ -e "$d"/123.dat ]]; then
cp -r "$d" /location2/parent
done
fi
作为 CLI 单行命令,它将是:
mkdir -p /location2/parent; for d in /location1/parent/*; do if [[ -e "$d"/123.dat ]]; then cp -r "$d" /location2/parent; done; fi
可以通过使用来find
提高效率并添加多级子目录,或者将源目录、目标目录和要搜索的文件放入变量中来改进这一点。这应该可以满足您目前的需求。
如果要复制一个包含特定文件的目录,但不复制任何其他文件,有一个不太优雅的解决方案,它需要cd
进入源目录,cd -
最后的部分会返回到原始目录:
mkdir -p /location2/parent; cd /location1/parent/ && for d in ./*; do if [[ -e "$d"/123.dat ]]; then cp --parents "$d"/123.dat /location2/parent/; fi ; done; cd -
作为多行:
mkdir -p /location2/parent
cd /location1/parent/ && for d in ./*
do
if [[ -e "$d"/123.dat ]]; then
cp --parents "$d"/123.dat /location2/parent/
fi
done
cd -