我需要复制 /parent 下的所有文件夹(到新位置),但前提是它有 123.dat - 在这种情况下,我也需要复制该文件夹,但不复制它包含的任何其他文件。
所以这个:
|parent
| |a
| | 123.dat
| | 456.dat
| |b
| | 123.dat
| | 789.dat
| |c
| | 456.dat
| | 789.dat
Run Code Online (Sandbox Code Playgroud)
变成:
|parent
| |a
| | 123.dat
| |b
| | 123.dat
Run Code Online (Sandbox Code Playgroud)
我如何在 linux 中做到这一点?这个领域不是我的专长,到目前为止,我尝试寻找类似的东西没有成功。
一种方法是在新位置创建新版本的父目录,然后跨子目录复制(如果它们包含 123.dat)。这使用 Bash shell 的 globbing 功能来查找子目录,因此只能在父目录下的目录上工作。在这个例子中,我假设 parent 位于一个名为的目录中/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
Run Code Online (Sandbox Code Playgroud)
作为 CLI one-liner,这将是:
mkdir -p /location2/parent; for d in /location1/parent/*; do if [[ -e "$d"/123.dat ]]; then cp -r "$d" /location2/parent; done; fi
Run Code Online (Sandbox Code Playgroud)
可以通过使用find使其更高效并添加多级子目录,或将源目录、目标目录和文件放入变量中来改进这一点。这应该做你现在需要的。
要复制包含特定文件的目录,但不复制任何其他文件,有一个不太优雅的解决方案,需要cding 进入源目录,最后的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 -
Run Code Online (Sandbox Code Playgroud)
作为多行:
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 -
Run Code Online (Sandbox Code Playgroud)
文件/文件夹结构:
$ 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
Run Code Online (Sandbox Code Playgroud)
复制匹配的文件,保留相对路径(浅,不超过 1 个文件夹):
命令:
$ (cd src && cp -v --parents */123.dat ../dest)
Run Code Online (Sandbox Code Playgroud)
输出:
a -> ../dest/a
'a/123.dat' -> '../dest/a/123.dat'
b -> ../dest/b
'b/123.dat' -> '../dest/b/123.dat'
Run Code Online (Sandbox Code Playgroud)
(和)为了不使用时改变原来的工作目录cd。我不得不进入src执行前cp,以不建立src/在底层目录dest。替代方法(使用find可调深度限制):
命令:
$ (cd src && find . -maxdepth 2 -type f -name '123.dat' -exec cp -v -t "../dest" --parents {} +)
Run Code Online (Sandbox Code Playgroud)
输出:
./b -> ../dest/./b
'./b/123.dat' -> '../dest/./b/123.dat'
./a -> ../dest/./a
'./a/123.dat' -> '../dest/./a/123.dat'
Run Code Online (Sandbox Code Playgroud)
笔记:
(和)为了不使用时改变原来的工作目录cd。我不得不进入src执行前find,以不建立src/在底层目录dest。-type f确保只123.dat考虑具有名称的文件,而不是碰巧具有该名称的目录替代方法(使用rsync,没有深度限制):
命令:
$ rsync -rv --include=123.dat --include='*/' --exclude='*' --prune-empty-dirs src/ dest
Run Code Online (Sandbox Code Playgroud)
输出:
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
Run Code Online (Sandbox Code Playgroud)
再检查一遍:
$ find dest
dest
dest/b
dest/b/123.dat
dest/a
dest/a/123.dat
Run Code Online (Sandbox Code Playgroud)
笔记:
/的src/是故意的,因此,只有该文件夹的内容被复制,而不是文件夹本身。--exclude='*' 默认情况下排除所有内容--include='*/ 覆盖排除并包括所有文件夹--include='123.dat' 覆盖排除并包含名称为“123.dat”的文件(和文件夹)--prune-empty-dirs确保没有创建空文件夹(例如c)