仅当目录包含指定文件时才复制Linux中的目录

仅当目录包含指定文件时才复制Linux中的目录

我需要复制 /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 -

相关内容