Копирование нескольких конкретных файлов из одной папки в другую


133

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


Fyi, для копирования определенных папок используйте:, cp -rp /copying/from/{folder1/,folder2/,folder3/} path/to/folderгде pдля копирования разрешений папки.
Рактим Бисвас

Ответы:


179

Просто скопируйте несколько файлов одновременно из командной строки

Есть несколько способов добиться этого. Самое простое, что я видел, это использовать следующее.

cp /home/usr/dir/{file1,file2,file3,file4} /home/usr/destination/

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

Обязательно обратите внимание, что между файлами нет пробелов. Последняя часть команды, /home/usr/destination/это каталог, в который вы хотите скопировать файлы.

или если все файлы имеют одинаковый префикс, но разные окончания, вы можете сделать что-то вроде этого:

cp /home/usr/dir/file{1..4} ./

Где файл1, файл2, файл3 и файл4 будут скопированы.

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

Работа с дубликатами с питоном

Поэтому я написал небольшой скрипт на python, который, я считаю, должен выполнить работу. Однако я не уверен, насколько хорошо вы разбираетесь в python (если вообще разбираетесь), поэтому я постараюсь объяснить, как использовать этот скрипт наилучшим образом, и, пожалуйста, задайте столько вопросов о нем, сколько вам нужно.

import os,sys,shutil
### copies a list of files from source. handles duplicates.
def rename(file_name, dst, num=1):
    #splits file name to add number distinction
    (file_prefix, exstension) = os.path.splitext(file_name)
    renamed = "%s(%d)%s" % (file_prefix,num,exstension)

    #checks if renamed file exists. Renames file if it does exist.
    if os.path.exists(dst + renamed):
        return rename(file_name, dst, num + 1)
    else:
        return renamed

def copy_files(src,dst,file_list):
    for files in file_list:
        src_file_path = src + files
        dst_file_path = dst + files
        if os.path.exists(dst_file_path):
            new_file_name =  rename(files, dst)
            dst_file_path = dst + new_file_name

        print "Copying: " + dst_file_path
        try:
            shutil.copyfile(src_file_path,dst_file_path)
        except IOError:
            print src_file_path + " does not exist"
            raw_input("Please, press enter to continue.")

def read_file(file_name):
    f = open(file_name)
    #reads each line of file (f), strips out extra whitespace and 
    #returns list with each line of the file being an element of the list
    content = [x.strip() for x in f.readlines()]
    f.close()
    return content

src = sys.argv[1]
dst = sys.argv[2]
file_with_list = sys.argv[3]

copy_files(src,dst,read_file(file_with_list))

Этот скрипт должен быть относительно простым в использовании. Прежде всего, скопируйте приведенный выше код в программу gedit (должна быть предварительно установлена ​​в Ubuntu) или в любой другой текстовый редактор.

После этого сохраните файл как move.py в вашем домашнем каталоге (это может быть любой каталог, но для простоты инструкций просто используйте домашний каталог) или добавьте каталог, в котором находится файл, в вашу переменную PATH. Затем cdв свой домашний каталог (или любой другой каталог, в котором вы сохранили move.py) из терминала и введите следующую команду:

python move.py /path/to/src/ /path/to/dst/ file.txt

Это должно скопировать все файлы, перечисленные из исходного каталога в каталог назначения с дубликатами в формате pic (1) .jpg, pic (2) .jpg и так далее. file.txt должен быть файлом, в котором перечислены все изображения, которые вы хотите скопировать с каждой записью в отдельной строке.

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

Примечания

  • Этот сценарий предполагает, что все исходные изображения находятся в одном каталоге. Если вы хотите, чтобы он также проверял подкаталоги, скрипт необходимо будет изменить.
  • Если вы случайно набрали неверное имя файла, скрипт выдаст сообщение об ошибке
    «файл не существует» и предложит вам «нажать ввод», чтобы продолжить, и скрипт продолжит копирование остальной части списка.
  • Не забудьте завершить /как путь к исходному
    каталогу, так и путь к конечному каталогу. В противном случае скрипт выдаст вам ошибку.

Спасибо, это решило большую часть моей проблемы, однако некоторые файлы появляются в списке дважды или более. Как мне сделать так, чтобы эти дубликаты автоматически переименовывались? (Да, мне нужны дубликаты для того, что я делаю.)
кого-то слишком много пиктов

Это дубликаты из разных подпапок или они помечены как file.jpg и file (1) .jpg? в противном случае я не уверен, как у вас есть файлы, которые идентичны. Чтобы хоть немного ответить на ваш вопрос, я не верю, что вы сможете найти простой вкладыш, который будет автоматически переименовывать дубликаты для вас. Я думаю, что bash или какой-то другой тип сценария должен был бы быть написан, чтобы получить такую ​​функциональность. Тем не менее, я видел несколько довольно нелепых однострочных команд, так что, может быть, появится какой-нибудь мастер linux и даст ответ.
Брайан

Первоначально у меня был только один файл, но имена файлов указаны в списке дважды или более. Более или менее то, что мне нужно для этого, при попытке поместить файл в новую папку, и файл с таким именем уже существует, мне нужно для него добавить (2) или около того в конец имени файла и поместите это.
кого-то слишком много пиктов

Я просто хочу предложить подчеркнуть, что в списке файлов для копирования нет пробелов. Если есть пробелы, даже между файлами {foo, bar, ..}, команда работать не будет.
Франкс

Для тех, кто ищет дополнительные ярлыки, вы можете использовать подстановку команд, чтобы заменить абсолютный путь к файлам, т. cp $(pwd)/{file1,file2} /path/to/dst/cp $(pwd)/{file1,file2} $(pwd)/{renamed1,renamed2}
Е.

50

Возможно, мне не хватает детали вашего вопроса, но приведенные ответы кажутся излишними. Если вам нужно решение для командной строки, а не сценарий, почему бы и нет:

cd /path/to/src/
cp -t /path/to/dst/ file1 file2 file3 ...

Хорошая вещь в том, что вы можете делать это таким образом, что вы можете вкладывать имена файлов


5
Это возвращает «недопустимую опцию --t» в macOS Sierra
geoyws

Отличный ответ, гораздо проще. @geoyws Может быть, это версия POSIX или GNU, которой нет в версии Apple. Он отлично работает для меня на Debian Linux или Windows с MSYS2.
underscore_d

Хорошее предложение! работал в арке linux.
Эду Руис,

brew install coreutilsтогда вы можете получить обычные вещи GNU с gпрефиксом. Так и будетgcp -t ....
Т.Чмелевский

Mac OS использует версию BSD cp, и, в частности, ни OpenBSD, ни FreeBSD не имеют такой опции, так что да - это cp специфично для GNU . Это также не указано стандартом POSIX . Поскольку это сайт, специфичный для Ubuntu, это приемлемо, но для переноса скриптов между ОС лучше придерживаться стандарта POSIX
Сергей Колодяжный

7

Вот чистое решение Bash. Он будет читать имена файлов из входного файла (по одному в строке) и копировать каждое из них, переименовывая дубликаты.

#!/usr/bin/env bash

## The destination folder where your files will
## be copied to.
dest="bar";

## For each file path in your input file
while read path; do 
    ## $target is the name of the file, removing the path. 
    ## For example, given /foo/bar.txt, the $target will be bar.txt.
    target=$(basename "$path"); 
    ## Counter for duplicate files
    c=""; 
    ## Since $c is empty, this will check if the
    ## file exists in target.
    while [[ -e "$dest"/"$target"$c ]]; do
        echo "$target exists"; 
        ## If the target exists, add 1 to the value of $c
        ## and check if a file called $target$c (for example, bar.txt1)
        ## exists. This loop will continue until $c has a value
        ## such that there is no file called $target$c in the directory.
        let c++; 
        target="$target"$c; 
    done; 
    ## We now have everything we need, so lets copy.
    cp "$path" "$dest"/"$target"; 
done

Сохраните этот скрипт в своей папке $PATHи вызовите его со списком путей в качестве входных данных:

auto_copy.sh < file_paths.txt

Вы также можете запустить все это как команду из терминала:

while read path; do 
   target=$(basename "$path"); 
   c=""; 
   while [[ -e bar/"$target"$c ]]; do 
    echo "$target exists"; 
    let c++; 
    target="$target"$c; 
   done; 
   cp "$file" bar/"$target"; 
done < file_names;

1

Согласно описанию вопроса, я понимаю, что:

  • есть список файлов, предположительно текстовый файл input.txt
  • список содержит только имена файлов
  • есть определенный каталог, где находятся эти имена файлов.

Таким образом, можно использовать следующую команду:

xargs -I % --arg-file=input.txt cp  /path/to/origin_dir/%  /path/to/destination

Объяснение:

  • -I % указывает символ для текущего обработанного файла, который будет использоваться в команде
  • --arg-file=input.txt указывает принимать аргументы для команды из input.txt
  • cp /path/to/origin_dir/% /path/to/destination/выполнит cpкоманду с /path/to/origin_dir/%заменой /path/to/origin_dir/и именем обрабатываемого файла.

Практический пример:

$ cat input.txt
file2.txt
file1.txt
file3.txt
$ ls ./docs
file1.txt  file2.txt  file3.txt
$ xargs -I % --arg-file=input.txt cp ./docs/% ./docs_destination/
$ ls ./docs_destination/
file1.txt  file2.txt  file3.txt
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.