Как я нахожу и копирую произвольный список файлов в терминале?

Я пытаюсь получить голову вокруг нахождения файлов в терминале в данный момент. Я нашел много ответов о том, как найти файлы к определенному шаблону, такие как файлы, заканчивающиеся в определенном расширении, или с определенного периода времени, и т.д.

Что я пытался выяснить, тем не менее, то, как найти и скопировать несколько произвольных файлов, как список определенных файлов.

Скажите, например, у меня есть следующие папки и файлы

/Documents/Folder_1/ с содержанием:

file1.txt file2.txt file3.txt file4.txt

/Documents/Folder_2/ с содержанием:

file5.txt file6.txt file7.txt

/Documents/Folder_3/ с содержанием:

file8.txt, file9.txt

и то, что я хочу сделать, должно сделать новую папку названной Folder_4 и копия file2.txt, file5.txt и file9.txt к той новой папке.

Там какой-либо путь состоит в том, чтобы сделать это через терминал?

То, что я попытался сделать, должно войти в текстовый список имен файлов и назвать его чем-то как list.txt, например.

file2.txt
file5.txt
file9.txt

и загрузка того текстового файла в команду Find, например, как это:

find /home/usr/Documents -name $cat list.txt

со взглядами, что я затем подал бы вывод или к текстовому списку или к команде копии, но это, кажется, не работает.

Я задаюсь вопросом, существует ли какой-либо способ найти несколько произвольных файлов посредством команды Find, или я думаю об этом неправильным способом?

Править: Просто требуемый, чтобы сказать спасибо за ответы и суммировать способ, которым я закончил тем, что приблизился к этой проблеме. Я особенно ценю, что кто-то объяснил мне, что команда находки не разработана для принятия больше чем одного входа без флага-o, это заставило меня чувствовать себя немного менее глупым для неспособности понять это!

То, что я закончил тем, что делал, должно было сделать немного сценария оболочки и попросить ввод данных пользователем и использовать массив и, чтобы цикл выполнил итерации через список.

В основном сценарий, с которым я закончил, более или менее похож на это:

#!/bin/bash

#take user input
echo "Please enter list of filenames to search"
read list
echo "Please enter the folder path to search"
read path
echo "Please enter the destination folder path"
read destination

#use inputted list as input for array, and then use a for loop to find each item on list one by one
array=($list)
for i in "${array[@]}"
do
    find "$path" -iname "i" -exec cp '{}' "$destination" \;
done
4
задан 14 June 2018 в 13:14

3 ответа

Все еще пытаясь выяснить Ваш вопрос самым ясным способом.

Вы пытающийся найти некоторые определенные файлы в каталоге? Если да и существует шаблон, что Вы могли использовать регулярные выражения для нахождения их, затем используют find <directory> -regex "your_regex" и если нет никакого шаблона, Вам нужно указывание имен файлов, которые Вы ищете. Можно использовать сценарий Python ниже для копирования файлов.

import shutil
import os

list = [file1.txt, file2.txt] # replace with your file list.
destination = "your_destination" # replace with your destination.
directory = os.getcwd() # replace os.getcwd() with your directory.

for dirpath, dirname, filenames in os.walk(directory, topdown='true'):
    for file in filenames :
        if file in list :
            shutil.copy(os.path.join(dirpath, file), destination) 

, Если вышеупомянутое не является Вашим случаем затем, я предлагаю использовать это:

find <somewhere> -name "something" | xargs cp -t <your_destination>
0
ответ дан 1 December 2019 в 09:46

К сожалению, find команда -name предикат только принимает единственный шаблон. Если бы Вы хотите искать несколько файлов по имени, необходимо было бы объединить их в цепочку с -o (логичный OR) оператор - что-то как:

find Documents/ \( -name "file2.txt" -o -name "file5.txt" -o -name "file9.txt" \) -print

Это делает это хитрым для построения поиска программно из списка; самое близкое я могу прийти к Вашей предпринятой команде:

  1. прочитайте список в массив оболочки

    mapfile -t files < list.txt
    
  2. используйте оболочку удара printf создать список предиката

    printf -- '-name "%s" -o ' "${files[@]}"
    
  3. использовать eval оценить получающуюся командную строку

Существует морщина здесь поскольку, если мы используем printfфункция повторного использования формата для построения списка таким образом нас оставляют со 'свисанием' -o; мы можем работать вокруг этого путем завершения списка с a -false тест (так как -o -false булевская переменная не) так, чтобы наша заключительная строка предиката стала

"\( $(printf -- '-name "%s" -o ' "${files[@]}") -false \)"

Соединение всего этого - данный

$ 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

и

$ cat list.txt
file2.txt
file5.txt
file9.txt

затем

$ 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

Для копирования файлов вместо того, чтобы просто перечислить их Вы могли затем сделать

$ mkdir newdir
$ eval find dir/ "\( $(printf -- '-name "%s" -o ' "${files[@]}") -false \)" -exec cp -t newdir/ -- {} +

получающийся в

$ tree newdir
newdir
├── file2.txt
├── file5.txt
└── file9.txt

0 directories, 3 files

Примечание: eval команда мощна, и потенциально откройтесь к злоупотреблению: используйте с осторожностью.


На практике, учитывая, что Вы, кажется, хотите найти только небольшое количество файлов, подход KISS должен был бы принять хит производительности нескольких find вызовы и просто используют цикл:

while read -r f; do
  find dir/ -name "$f" -exec cp -v -- {} newdir/ \;
done < list.txt

или даже использование xargs

xargs -a list.txt -n1 -I@ find dir/ -name @ -exec cp -v -- {} newdir/ \;
4
ответ дан 1 December 2019 в 09:46

Сценарий удара ниже, если выполняется из высокоуровневого каталога (говорят от Вашего ~/Documents папка), будет создавать новый каталог и копировать/перемещать файлы, которые Вы хотите. По умолчанию это только повторяет найденные файлы, так, чтобы пользователь мог проверить, является ли это результатом, они хотели бы.Примечание: замена echo с cp скопировать или mv перемещаться.

Списку файлов присваивают regex переменная с \| разделитель (который для grep означает логичный или оператор),

copy_files.sh:

#!/bin/bash
new_dir="./dir4"
[ -d "$new_dir" ] ||  mkdir "$new_dir"
regex="file1\|file3\|file6"
find . -print0 | while IFS= read -d $'\0' line;
do
    if grep -q "$regex" <<< $line
    then
       filename=$(basename "$line")
       printf "%s\n" "Found $filename"
       echo "$line" "$new_dir"/"$filename"
       # Replace echo with cp for copying,
       # or mv for moving
    fi   
done
bash-4.3$ ./copy_files.sh 
Found file6
./dir3/file6 ./dir4/file6
Found file3
./dir1/file3 ./dir4/file3
Found file1
./dir1/file1 ./dir4/file1

Поскольку Вы видите выше, отчеты сценария, какой файл был найден и где он скопирует его или перемещение, например, в последней строке, он копировал бы/перемещал бы ./dir1/file1 кому: ./dir4/file1 если это на самом деле использовало cp или mv и не просто echo

0
ответ дан 1 December 2019 в 09:46

Другие вопросы по тегам:

Похожие вопросы: