Як скопіювати декілька файлів на підстановку?


42

У мене папка з кількома файлами в ній ABC. * (Таких файлів приблизно 100). Я хочу копіювати їх у нові файли з іменами, що починаються з DEF. *

Отже, я хочу

ABC.Page1
ABC.Page2
ABC.Topic12
...etc

скопійовано в

DEF.Page1
DEF.Page2
DEF.Topic12
...etc

Який найпростіший спосіб зробити це за допомогою команди batch (у BASH чи подібних)? Я думаю про щось, що стосується sed, awk або xargs, але мені важко з'ясувати синтаксис. Я міг би написати сценарій Python, але я думаю, що, ймовірно, є рішення командного рядка, яке не надто складне.


Поважний mcменеджер файлів має найбільш широку підтримку такого роду масових перейменовань.
oakad

@oakad tarтакож не є весняно- курчатою . Дивіться мою відповідь для прикладу.
mikeserv

Відповіді:


41

Як щодо щось подібне в баші:

for file in ABC.*; do cp "$file" "${file/ABC/DEF}";done

Ви можете перевірити це, поставивши ехо перед командою cp:

for file in ABC.*; do echo cp "$file" "${file/ABC/DEF}";done

досконалий. навіть простіше, ніж я собі уявляв.
Восьминіг

У більшості випадків це буде досить добре, але тут важливо перевірити відлуння. Ніколи не робіть цього за сценарієм . Для отримання додаткової інформації читайте підводні камені
pawel7318

@ pawel7318, посилання, яке ви дали, хоч і чудова порада, схоже, не стосується команди, наведеної вище. Єдині випадки країв , які я бачу з цією командою: (1) Не перевіряє , якщо цільовий файл вже існує , ні , якщо цільовий файл вже існує у вигляді каталогу (який буде копіювати файл в директорію, зберігаючи свою нинішню назву), та (2) якщо файлів так багато, що глобальне розширення не може вписатися в один командний рядок.
Wildcard

1
Я розумію це: cp /usr/local/lib/libboost* /usr/local/lib/libboost*за допомогою ехо-перевірки.
Томаш Зато

8

Щоб зробити це ефективно з великою кількістю файлів, краще уникати запуску іншого cpпроцесу для кожного. Одним із способів було б скопіювати, а потім перейменувати їх за допомогою prename( renameпосиланням на це за замовчуванням в дистрибутивах на основі Debian). Використовуючи це та Linux mktemp:

tmp=$(mktemp -d --tmpdir=.)
cp ABC.* "$tmp"
prename "s:$tmp/ABC:DEF:" "$tmp/"*
rmdir "$tmp"

Оновлення

Насправді paxможе бути кращий спосіб поїхати сюди:

pax -rws '/^ABC/DEF/' ABC.* .

На жаль, незважаючи на paxте , що вони є POSIX та Linux Standard Base, в даний час деякі дистрибутиви включають його за замовчуванням.


приємний дотик, використовуючи: як роздільник, щоб уникнути втечі.
Клейтон Стенлі

5

tar зробить це для вас дуже швидко.

ТЕСТ

Спочатку я створив 2 каталоги та 10 файлів:

% mkdir test1 test2 ; cd test1
% for n in `seq 1 10` ; do touch ABC.file$n ; done
% ls

> ABC.file1   ABC.file2  ABC.file4  ABC.file6  ABC.file8
> ABC.file10  ABC.file3  ABC.file5  ABC.file7  ABC.file9

Потім я скопіював їх:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC/DEF/' -xf -
% ls ../test2

> DEF.file1   DEF.file2  DEF.file4  DEF.file6  DEF.file8
> DEF.file10  DEF.file3  DEF.file5  DEF.file7  DEF.file9

ТРАНСФОРМАЦІЯ

Таким чином, GNU tarприйме sed --transform=EXPRESSIONперейменування файлів. Це навіть може перейменувати лише деякі файли. Наприклад:

% tar -cf - ./* |\ 
    tar -C../test2 --transform='s/ABC\(.*[0-5]\)/DEF\1/' -xf -
% ls ../test2

> ABC.file6  ABC.file8  DEF.file1   DEF.file2  DEF.file4
> ABC.file7  ABC.file9  DEF.file10  DEF.file3  DEF.file5

Тож це одна перевага.

СТРАЙ

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

tar | tar

tarнастільки оптимізований, як ви могли б хотіти. Це ніколи не матиме підрахунку проблем або аргументованих дочірніх процесів. Це просто A> B зроблено.

АРГУМЕНТИ

Тут я використовую 7 різних аргументів, поєднаних між двома моїми tarпроцесами. Перший тут перерахований найважливіший:

-stdout / stdin - це повідомляє, tarщо він буде передавати або його вхід, або вихід на нього, або з stdin/stdoutякого він буде інтерпретувати правильно залежно від того, будує він чи витягує архів чи ні.

-ccreate - це говорить tarпро створення архіву. Наступний аргумент tarочікує:

-fФайл - ми вказуємо, що tarбуде працювати з fileоб'єктом, а не стрічковим пристроєм чи будь-яким іншим. А файл, з яким він буде працювати, як зазначалося вище, є stdin/stdout- іншими словами, наш |pipe.

./*всі $ PWD / файли - не надто багато для пояснення тут, за винятком того, що аргумент архіву приходить спочатку, тож -потім ./*.

... і з іншого боку |pipe...

-Cкаталог змін - це інформує, tarщо його потрібно змінити в вказаний я каталог перед виконанням будь-якої іншої дії, тому ефективно це безпосередньо cd ../test2перед вилученням.

--transform='s/ed/EXPR/'- як уже згадувалося, це перейменувало. Але документи вказують, що він може приймати будь-який sedвираз або //flag.

-xвитяг - після tarзмін у нашому цільовому каталозі та отримання наших інструкцій з перейменування ми доручаємо йому розпочати вилучення всіх файлів у його поточний каталог з -f - |pipeархівного файлу. Ніякої таємниці.


1
Ось paxвирішення цього питання. Я би додав це до своєї відповіді, але я думаю, що тут краще підходить -pax -rws '/^ABC/DEF/' ABC.* .
Graeme

@Graeme - woah - так краще! Людина, це теж пекло перейменування перлів! Ви повинні вказати це у своїй відповіді - paxчи вказано POSIX - отже pax.
mikeserv

paxможе бути POSIX, але він, на жаль, рідко встановлюється за замовчуванням.
Graeme

4

Якщо ви не заперечуєте проти використання менш стандартного інструменту, рекомендую використовувати mmv (масовий хід), який був написаний для таких самих завдань. Використовуючи mcp(масову копію), що входить до складу набору, ви могли просто зробити

mcp "ABC.*" "DEF.#1"

Знайти пакети для завантаження не зовсім просто. Поточний пакет Debian (який Arch також використовує в AUR) для збирання вдома можна знайти тут .


встановлюється на ubuntu 15.10 з коробки,apt-get install mmv
Туфір,


1

Ви можете зробити це:

for i in ABC.*; do cp {ABC,DEF}."${i#*.}"; done

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

Це моє погано, я неправильно прочитав вашу відповідь. :-)
Кріс Даун

Як я повинен прочитати "${i#*.}"шматочок?
dumbledad

-1

1
Ласкаво просимо до Unix & Linux! Хоча це теоретично може відповісти на питання, бажано було б сюди включити істотні частини відповіді та надати посилання для довідки.
terdon
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.