Копіювання декількох певних файлів з однієї папки в іншу


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 (якщо він взагалі розбирається), тож я спробую пояснити, як використовувати цей сценарій найкращим чином, і, будь ласка, задайте стільки запитань щодо нього, скільки вам потрібно.

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 має бути файлом, у якому перераховані всі зображення, які ви хочете скопіювати, з кожним записом, в окремому окремому рядку.

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

Примітки

  • Цей сценарій передбачає, що всі початкові зображення є в одному каталозі. Якщо ви хочете, щоб він також перевіряв підкаталоги, сценарій потрібно буде змінити.
  • Якщо ви випадково ввели ім’я файлу, скрипт виплюне помилку
    "файл не існує" і запропонує "натиснути Enter", щоб продовжити, і сценарій продовжить копіювати решту списку.
  • Не забувайте про тривалість /як шляху до вихідного
    каталогу, так і шляху до каталогу призначення. Інакше скрипт поверне вам помилку.

Дякую, що вирішили більшу частину моєї проблеми, проте деякі файли з’являються у списку двічі чи більше, як я можу зробити так, щоб перейменувати ці копії автоматично? (Так, мені потрібні дублікати для того, що я роблю.)
Хтось із занадто великою кількістю зображень

Чи є дублікати з різних підпапок або вони мають щось на зразок file.jpg та file (1) .jpg? інакше я не впевнений, як у вас є файли, які однакові. Щоб дещо відповісти на ваше запитання, я не вірю, що ви зможете знайти простий на вкладиші, який автоматично перейменує копії для вас. Я думаю, що для отримання такого типу функціональності повинен бути написаний bash або якийсь інший тип сценарію. Однак я бачив кілька досить смішних команд з одного рядка, тож можливо, якийсь майстер Linux може з’явитися і дати відповідь.
Брайан

У мене є лише один файл кожного файлу спочатку, однак назви файлів є у списку двічі чи більше. Більше чи менше, що мені потрібно для цього, коли я намагаюся розмістити файл у новій папці, а файл із таким ім’ям вже існує, мені потрібно додати до нього (2) або так до кінця імені файлу і розмістіть його.
Хтось із занадто великою кількістю зображень

Я просто хочу запропонувати наголосити на частині того, що у списку файлів для копіювання немає пробілів. Якщо є пробіли, навіть між файлами {foo, bar, ..} команда не буде працювати.
франки

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

49

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

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

Приємна річ у цьому способі - це те, що ви можете вкладати повні імена файлів


5
Це повертає "незаконний варіант --t" у macOS Sierra
geoyws

Чудова відповідь, куди простіша. @geoyws Можливо, у версії Apple немає речі POSIX або GNU. Для мене це добре працює на Debian Linux або Windows з MSYS2.
підкреслюй_d

приємна пропозиція! працював в arch linux.
Еду Руїз

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

Mac OS використовує версію BSD cp, і особливо OpenBSD і FreeBSD не мають такої опції, так що так - це cp специфічно для GNU . Він також не визначений стандартом POSIX . Оскільки це специфічний для Ubuntu сайт, це прийнятно, але для перенесення скриптів між ОС краще дотримуватися стандарту POSIX
Сергій Колодяжний,

7

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

#!/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.