我有一个巨大的文件夹树,每个文件夹都有多个子目录,大约向下 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
.非常感谢您的帮助!我想这会涉及find
和cp
,但似乎无法解决,
答案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