仅将列表中的文件复制到大型目录结构中的新目录中

仅将列表中的文件复制到大型目录结构中的新目录中

由于我正在准备一本书,所以我收集了大量花卉图片。我只会使用其中的一些图片,它们包含在一个名为choosen.txt(实际上是一个csv)的文件中。我必须从按以下方式组织的文件夹树中挑选出选定的图片:

Pictures
├── Flowers 2020
│   ├── 1.- Spring 2020
│   ├── 2.- Summer 2020
│   ├── 3.- Autumn 2020
│   └── 4.- Winter 2020
└── Flowers 2021
    ├── 1.- Spring 2021
    ├── 2.- Summer 2021
    ├── 3.- Autumn 2021
    └── 4.- Winter 2021

10 directories, 5260 files

并将每张选定的花朵图片复制到名为 Chosen-ones 的新文件夹中(例如)。希望我已经正确解释了我需要做什么。

以下是 csv 文件的几行chosen.txt

DSC10233.jpg
DSC10276.jpg
DSC10288.jpg
DSC10399.jpg
DSC10448.jpg
DSC10489.jpg
DSC10492.jpg

是否可以使用 Bash 或者 Python 脚本?

提前致谢。

答案1

当然,您可以使用一个非常小的 Bash 脚本来完成此操作。

我假设您chosen.txt的主目录中有该列表,其中 Pictures 是其子目录。如果不是这种情况,请相应地调整路径。

首先创建要将文件移动到的目录。我假设您刚刚打开了一个终端,并且您位于主目录中。您可以稍后移动该目录。

mkdir ChosenOnes

现在检查您是否可以使用这样的列表找到正确的文件:

while read -r line; do find Pictures -name "$line" -ls; done < chosen.txt

如果结果看起来正确,您可以通过调整命令来复制文件:

while read -r line; do find Pictures -name "$line" -exec cp -vt ChosenOnes {} \; ; done < chosen.txt

我们可以让它看起来更好一些:

#!/bin/bash
# read our list and
while read -r line; do
  # find the files in it and copy them to the new directory
  find Pictures -name "$line" -exec cp -vt ChosenOnes {} \;
done < chosen.txt

解释

  • while read -r line; do things; done < input-file只要条件成立,循环while就会继续执行某项操作。这里我们要求逐行读取列表。每一行都将被放入变量中,line以便我们可以在其上运行一些命令。当我们完成该行上的命令后,将读取下一行,直到文件中的行数用完为止。
  • find path -name "$line"find命令从给定路径(本例中为图片)向下进行递归搜索。这里我们使用该-name选项查找与列表中的名称匹配的文件。
  • -lsfind命令有一个选项可以列出找到的文件。这对于在采取任何行动之前检查找到的内容很有用
  • -exec command {} \;find选项-exec对已找到的文件运行给定的命令(由 表示{}
  • cp -vt选项-vmakescp告诉我们它在做什么。-t选项指定目标(我们在它之后立即给出目标目录);否则目标将被视为最后一个参数。

答案2

是的,命令行上有几种方法可以做到这一点。

假设您只有一个文件名列表(没有路径),您可以使用循环while读取“chosen.txt”文件,find查找源文件夹中的文件,然后使用另一个while循环复制它们。

定义变量使您可以重复使用长命令而无需编辑它。

list="/path/to/chosen.txt"
source="/path/to/Pictures"
dest="/path/to/destination"
cat "chosen.txt" \
| while read n; do 
      find "$source" -name "$n" \
      | while read f; do
            cp "$f" "$dest/"
        done
  done

或者在一行中:

cat "chosen.txt" | while read n; do find "$source" -name "$n" | while read f; do cp "$f" "$dest/"; done; done

另一种方法是,如果您的原始 .csv 文件也包含文件路径,则可以从中构建一个列表。然后,您可以使用rsync选项--files-from=复制它们,同时保留源的原始目录结构。

相关内容