Как скопировать несколько файлов по шаблону?


42

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

Я хочу

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

скопированы в

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

Какой самый простой способ сделать это с помощью пакетной команды (в BASH или аналогичной)? Я думаю о чем-то, касающемся sed, awk или xargs, но мне сложно разобраться в синтаксисе. Я мог бы написать скрипт на Python, но я думаю, что, возможно, есть решение для командной строки, которое не слишком сложно.


У почтенного mcфайлового менеджера есть самая обширная поддержка для такого рода массовых переименований.
oakad

@oakad тоже tarне весенний цыпленок. Смотрите мой ответ для примера.
mikeserv

Ответы:


41

Как насчет этого в bash:

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

Вы можете проверить это, поместив echo перед командой cp:

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

идеальный. даже проще, чем я себе представлял.
Осьминог

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

@ pawel7318, ссылка, которую вы дали, хотя и отличный совет, похоже, не относится к приведенной выше команде. Единственные крайние случаи, которые я вижу с этой командой: (1) не проверяет, существует ли целевой файл уже или не существует ли целевой файл как каталог (который будет копировать файл в каталог, сохраняя его текущее имя), и (2) если файлов так много, что расширение glob не может поместиться в одной командной строке.
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, лишь немногие дистрибутивы в настоящее время включают ее по умолчанию.


приятно использовать: в качестве разделителя, чтобы избежать экранирования.
Клэйтон Стэнли,

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которые он будет интерпретироваться правильно, в зависимости от того, создает он или извлекает архив.

-cсоздать - это говорит tarо создании архива. Следующий аргумент tarожидает ...

-ffile - мы указываем, что tarбудем работать с fileобъектом, а не с ленточным устройством или чем-то еще. И файл, с которым он будет работать, как отмечалось выше, stdin/stdout- другими словами, наш |pipe.

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

... и на другой стороне |pipe...

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

--transform='s/ed/EXPR/'- как уже упоминалось, это было сделано переименование. Но документы указывают, что это может принять любое sedвыражение или //flag.

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


1
Вот paxрешение этого вопроса. Я бы добавил его в свой ответ, но я думаю, что он лучше подходит здесь -pax -rws '/^ABC/DEF/' ABC.* .
Грэм,

@ Грэм - вау - так лучше! Черт возьми, это бьет из жемчуга переименовать тоже! Вы должны paxуказать это в своем ответе - указан POSIX - отсюда и pax.
mikeserv

paxможет быть POSIX, но, к сожалению, он редко устанавливается по умолчанию.
Грэм,

4

Если вы не возражаете против использования менее стандартного инструмента, я рекомендую использовать mmv (массовый ход), который был написан для такого рода задач. Используя mcp(массовое копирование), который является частью пакета, вы можете просто сделать

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

Найти загружаемые пакеты не так просто. Текущий пакет Debian (который Arch также использует в AUR) для компиляции дома можно найти здесь .


устанавливается на Ubuntu 15.10 из коробки,apt-get install mmv
Thufir

2

В zsh поместите следующие строки в ваш .zshrc:

autoload -U zmv
alias zmv='noglob zmv'
alias zcp='zmv -C'
alias zln='zmv -L'

Затем в командной строке вы можете запустить

zcp 'ABC(.*)' 'DEF$1'

или просто

zcp -W ABC.* DEF.*

В другой оболочке, если у вас установлен zsh:

zsh -c 'autoload zmv; noglob zmv -CW ABC.* DEF.*'

1

Вы могли бы сделать это:

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

Может быть, я чего-то не вижу, но как мне установить несколько пунктов назначения? Я использую цикл для каждого. Я тестировал код заранее, и он работал как положено, поэтому я буду признателен за ваше объяснение.
Сара Фаузия

Это мое плохо, я неправильно понял ваш ответ. :-)
Крис Даун

Как я должен читать "${i#*.}"немного?
17

-1

1
Добро пожаловать в Unix и Linux! Хотя это может теоретически ответить на вопрос, было бы предпочтительно включить основные части ответа здесь и предоставить ссылку для справки.
Тердон
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.