Я пытаюсь получить голову вокруг нахождения файлов в терминале в данный момент. Я нашел много ответов о том, как найти файлы к определенному шаблону, такие как файлы, заканчивающиеся в определенном расширении, или с определенного периода времени, и т.д.
Что я пытался выяснить, тем не менее, то, как найти и скопировать несколько произвольных файлов, как список определенных файлов.
Скажите, например, у меня есть следующие папки и файлы
/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
Все еще пытаясь выяснить Ваш вопрос самым ясным способом.
Вы пытающийся найти некоторые определенные файлы в каталоге? Если да и существует шаблон, что Вы могли использовать регулярные выражения для нахождения их, затем используют 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>
К сожалению, find
команда -name
предикат только принимает единственный шаблон. Если бы Вы хотите искать несколько файлов по имени, необходимо было бы объединить их в цепочку с -o
(логичный OR
) оператор - что-то как:
find Documents/ \( -name "file2.txt" -o -name "file5.txt" -o -name "file9.txt" \) -print
Это делает это хитрым для построения поиска программно из списка; самое близкое я могу прийти к Вашей предпринятой команде:
прочитайте список в массив оболочки
mapfile -t files < list.txt
используйте оболочку удара printf
создать список предиката
printf -- '-name "%s" -o ' "${files[@]}"
использовать 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/ \;
Сценарий удара ниже, если выполняется из высокоуровневого каталога (говорят от Вашего ~/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