将多个目录中的文件(如果其名称出现在列表中)复制到单个目录中

将多个目录中的文件(如果其名称出现在列表中)复制到单个目录中

我有一个巨大的文件夹树,每个文件夹都有多个子目录,大约向下 3 层。这是一个只有一个级别的示例:

$ tree
.
|-- AB.txt
|-- CD.txt
|-- destination_folder
|-- spreadsheet.txt
`-- subdirectory
    `-- EF.txt

2 directories, 4 files

我有一个我感兴趣的文件名列表,名为spreadsheet.txt

$ cat spreadsheet.txt 
AB.txt
CD.txt
EF.txt

我想将出现的所有文件复制spreadsheet.txt到一个文件夹中,例如destination_folder.非常感谢您的帮助!我想这会涉及findcp,但似乎无法解决,

答案1

每个文件名运行find一次,并假设没有文件名包含嵌入的换行符:

#!/bin/sh

mkdir -p destination_folder || exit 1
while IFS= read -r name; do
    find . -path ./destination_folder -prune -o \
        -type f -name "$name" -exec cp {} destination_folder \;
done <spreadsheet.txt

这首先在当前目录中创建目标目录(如果失败则终止)。然后,它逐行读取输入文件,并调用find以查找具有该名称的任何常规文件。每当我们在搜索中遇到目标目录时,都会通过find使用来明确避免目标目录。-prune

只要找到具有正确名称的文件,就会将其复制到目标目录。如果多个文件同名,则in中的副本destination_folder会被覆盖。

如果当前目录很大,或者文件名列表很长(但不是几千行),那么这将是一个缓慢的操作。因此我们可能会选择做一个单身的拨电至find。下面的代码假设它是用 eg 执行的,bash因为它使用数组:

#!/bin/bash

mkdir -p destination_folder || exit 1

names=()
while IFS= read -r name; do
    names+=( -o -name "$name" )
done <spreadsheet.txt

find . -path ./destination_folder -prune -o \
    \( "${names[@]:1}" \) -type f -exec cp -t destination_folder {} +

在这里,我还选择使用cp -t(GNUcp扩展)来尽可能cp少地调用,而不是每个找到的文件调用一次。

上面的代码构建了一个数组 ,names最终将采用正确的格式与 一起使用find。根据您问题中的示例,在上述代码末尾实际执行的命令将是

find . -path ./destination_folder -prune -o '(' -name AB.txt -o -name CD.txt -o -name EF.txt ')' -type f -exec cp -t destination_folder '{}' +

为了避免目标目录中的文件名冲突问题,如果您使用的是 GNU cp(例如在 Linux 系统上),请使用cp-b--backup选项。

在非 Linux 系统上,GNU通常在通过包管理器安装 GNU coreutils 后cp可用。gcp


最后一个脚本,但对于/bin/sh(无数组):

#!/bin/sh

mkdir -p destination_folder || exit 1

set --
while IFS= read -r name; do
    set -- -o -name "$name" "$@"
done <spreadsheet.txt

shift

find . -path ./destination_folder -prune -o \
    \( "$@" \) -type f -exec cp -t destination_folder {} +

答案2

一个简单的 for 循环:

for filename in $(cat spreadsheet.txt)
do
find . -name "$filename" -exec cp {} /destination/folder \;
done

相关内容