将所有子目录名称和具有特定扩展名的文件复制到新目录

Sta*_*ess 5 command-line

我有以下目录结构:

dir1
    py1.py
    py2.py
    subdir1
        file1.py
        anotherfile.txt
    subdir2
        file2.py
        animage.png
Run Code Online (Sandbox Code Playgroud)

我想将文件夹结构和 *.py 文件(除了那些直接属于 dir1 的文件)复制到与 dir1 相同级别的新目录中。也就是说,我正在寻找这个:

dir2
    subdir1
        file1.py
    subdir2
        file2.py
Run Code Online (Sandbox Code Playgroud)

我试过(从 dir1 上面的层):

mkdir dir2
cp -r *.py ../dir2
Run Code Online (Sandbox Code Playgroud)

但这只是将 *.py 文件从 dir 1 复制到 dir2,而忽略了子目录。

Raf*_*ffa 2

您可以使用findand来完成此操作cpio,只需cd进入dir1并运行以下命令:

find . -mindepth 2 -type f -name "*.py" -print | cpio -pdm ../dir2
Run Code Online (Sandbox Code Playgroud)
  • find .将从当前目录开始,即。dir1
  • -mindepth 2将忽略当前目录的内容,即。dir1并包含其子目录的内容。
  • -type f -name "*.py" -print将仅包含具有.py扩展名的文件。
  • cpio -pdm会复制。-p创建文件列表,-d根据需要创建目录并-m设置目录的正确修改时间。

  • ../dir2dir2将创建一个名为旁边一级的目录(如果不存在)dir1并将所有内容复制到其中。

供参考man findman cpio

祝你好运


小智 0

好吧,我找不到一种方法让 cp 或 rsync 自己做你想做的事,所以我想出了:

for n in dir1/* ; do ls ${n}/*.py >/dev/null 2>&1 ; if [[ $? == 0 ]]; then mkdir dir2/${n/dir1\//} ; cp ${n}/*.py dir2/${n/dir1\//} ; fi ; done
Run Code Online (Sandbox Code Playgroud)

正确缩进可以使其更具可读性:

for n in dir1/* 
do
  ls ${n}/*.py >/dev/null 2>&1 
  if [[ $? == 0 ]]
  then
    mkdir dir2/${n/dir1\//} 
    cp ${n}/*.py dir2/${n/dir1\//} 
  fi
done
Run Code Online (Sandbox Code Playgroud)

所以,我正在做的是查看 dir1,假设每个文件都是一个目录,并尝试列出所有 *.py 文件(输出和错误消失在 /dev/null 中)。显然,对 py1.py 和 py2.py 尝试此操作将会失败,因为它们不是目录。对于其中没有任何 *.py 文件的任何目录,它也应该失败。

这意味着当我们在 if 中时,前一个命令 ($?) 的结果应该不是 0,并且我们什么也不做。对于 dir1 中的子目录,列表应该成功,所以 $? 将为 0,因此我们在循环内执行该位。这只是在 dir2 中创建子目录(记住将“dir1/”替换为空),并复制所有 *.py 文件。

这当然不是执行此操作的唯一方法,虽然它适用于您给出的示例,但如果子目录中有额外级别的子目录,则它不起作用。(例如dir1/subdir1/subsubdir1/*.py不会复制)