Infelizmente, o predicado find
do comando -name
aceita apenas um único padrão. Se você quiser pesquisar vários arquivos pelo nome, será necessário encadeá-los com o operador -o
(logical OR
) - algo como:
find Documents/ \( -name "file2.txt" -o -name "file5.txt" -o -name "file9.txt" \) -print
Isso dificulta a construção da pesquisa programaticamente a partir de uma lista; o mais próximo que eu posso chegar do seu comando é:
-
leia a lista em um array de shell
mapfile -t files < list.txt
-
use
printf
do shell bash para construir a lista de predicadosprintf -- '-name "%s" -o ' "${files[@]}"
-
use
eval
para avaliar a sequência de comandos resultante
Há um problema aqui, se usarmos o recurso de reutilização de formato de printf
para construir a lista dessa maneira, ficamos com um 'pendente' -o
; podemos contornar isso terminando a lista com um -false
test (já que -o -false
é um booleano não operacional) para que nossa string de predicado final se torne
"\( $(printf -- '-name "%s" -o ' "${files[@]}") -false \)"
Colocando tudo junto - dado
$ tree dir
dir
├── Folder_1
│ ├── file1.txt
│ ├── file2.txt
│ ├── file3.txt
│ └── file4.txt
├── Folder_2
│ ├── file5.txt
│ ├── file6.txt
│ └── file7.txt
└── Folder_3
├── file8.txt
└── file9.txt
3 directories, 9 files
e
$ cat list.txt
file2.txt
file5.txt
file9.txt
então
$ mapfile -t files < list.txt
$ eval find dir/ "\( $(printf -- '-name "%s" -o ' "${files[@]}") -false \)" -print
dir/Folder_1/file2.txt
dir/Folder_2/file5.txt
dir/Folder_3/file9.txt
Para copiar arquivos em vez de apenas listá-los, você pode fazer
$ mkdir newdir
$ eval find dir/ "\( $(printf -- '-name "%s" -o ' "${files[@]}") -false \)" -exec cp -t newdir/ -- {} +
resultando em
$ tree newdir
newdir
├── file2.txt
├── file5.txt
└── file9.txt
0 directories, 3 files
Observação: o comando eval
é poderoso e potencialmente aberto ao abuso: use com cuidado.
Na prática, considerando que você parece querer encontrar apenas um pequeno número de arquivos, a abordagem KISS seria para aceitar o hit de desempenho de várias chamadas de find
e apenas usar um loop:
while read -r f; do
find dir/ -name "$f" -exec cp -v -- {} newdir/ \;
done < list.txt
ou até mesmo usando xargs
xargs -a list.txt -n1 -I@ find dir/ -name @ -exec cp -v -- {} newdir/ \;