Фон
В Linux вы можете:
- Перечислите группу файлов с
ls Filename*
- Удалить группу файлов с
rm Filename*
- Переместить группу файлов с помощью
mv Filename* /New/Directory
- Но вы не можете скопировать группу файлов с:
cp Filename* *.bak
Изменить cp
команду Linux для копирования группы файлов
У меня есть группа файлов, которые я хотел бы скопировать, не вводя имена по одному и используя cp
команду:
$ ls gmail-meta3*
gmail-meta3 gmail-meta3-REC-1558392194-26467821
gmail-meta3-LAB-1558392194-26467821 gmail-meta3-YAD-1558392194-26467821
Как я могу использовать что-то вроде старой команды DOS copy gmail-meta3* *.bak
?
Я не хочу набирать подобную команду четыре раза:
cp gmail-meta3-LAB-1558392194-26467821 gmail-meta3-LAB-1558392194-26467821.bak
Я ищу скрипт / функцию / приложение, которое принимает параметры для старой и новой группы имен файлов, а не что-то с жестко закодированными именами файлов. Например, пользователь может ввести:
copy gmail-meta3* *.bak
или они могут напечатать:
copy gmail-meta3* save-*
command-line
cp
ms-dos
WinEunuuchs2Unix
источник
источник
touch aa ab ba; mkdir bb; cp a* b*; ls *
*
для исходных имен файлов, но не для целевых имен файлов. В качестве альтернативы подстановочный знак (я думаю, что это##
было предложено, но я склоняюсь%
) должен будет использоваться для цели. Я думаю, это то, что вы усиливаете? Я не ожидал изменитьcp
команду вообще. Просто создайте скрипт-обертку,copy
которая будет эмулировать (в пределах разумного) команду копирования DOS.Ответы:
Вот пример одного нетипичного использования
sed
, применимого для этой задачи:Таким образом, на самом деле,
sed
файлы не будут изменены, потому что мы не предоставили никаких команд''
, но из-за этой опции-i[suffix]
она создаст резервную копию каждого файла. Я нашел этот подход, когда искал. Есть ли способ создать резервную копию файла, не вводя его имя дважды?источник
$ time sed -i.bak '' gmail-meta3*
=real 0m0.069s
real 0m0.037s
. Если файлы удалены и запустить второй раз близко кcp
скорости:real 0m0.051s
.sed
быстрее, когда целевые файлы уже существуют, ноcp
медленнее, когда целевые файлы существуют. Я на самом деле сбрасываю кеш и буферы, а неsync
когда делаю большие временные тесты, но на этот раз я этого не делал. Поскольку это может отвлечься от совершенно другой тематической мыльной оперы, я сожалею, что поделился результатами своего теста :( Не слишком ли поздно сделать вид, что этого разговора никогда не было? Размер метаданных сообщения Gmail FYI составляет 2,5 МБ, а 3 файла индекса - около 800 КБ Также это не жесткий диск, это SSD Samsung Pro 960 NVMe на 4 каналахfree
команды. Фактическая запись на устройство происходит в момент, выбранный алгоритмом, который учитывает возраст кеша и нагрузку на память машины. Если вы пытаетесь выполнить несколько тестов, то первое чтение файла будет происходить с диска, но последующее чтение, скорее всего, будет происходить прямо из памяти (см.sync; echo 3 > /proc/sys/vm/drop_caches
).cp
команды, но я не могу сказать, что есть существенная разница в производительности .Вы можете использовать
find
:При этом в текущем каталоге будут найдены
.
все файлы с именем, совпадающим с шаблоном glob (обратите внимание на одинарные кавычки вокруг шаблона, чтобы предотвратить слипание оболочки). Для каждого найденного файла он будетcp
исполняться от имени к имени. \; в конце гарантирует, что он будет делать каждый файл отдельно, а не передавать их все сразу. Максимальная глубина, равная 1, ищет только каталог cuurent, а не рекурсию вниз.источник
find . -max-depth 1 -name '"$1"'' -exec cp "{}" "{}$2" \;
когда $ 1 является источником, а $ 2 является расширением?Вы можете использовать
for
цикл сbash
. Обычно я бы просто набрал его как однострочное, потому что это не та задача, которую я выполняю часто:Однако, если вам это нужно как скрипт:
Использование аналогично
rename
. Тестировать:источник
$ time for f in gmail-meta3* ; do cp -a "$f" "${f}.bak" ; done
=real 0m0.046s
0.046
секунды, что означает 0 секунд для человеческого восприятия. Я просто пытался показать, как я тестировал опубликованные ответы и передавал интересные кусочки зрителям, которые смотрели наsed
команду выше. Или, по крайней мере, я был заинтересован в сравненииsed
сcp
....cp
быстрее, чем решение сsed
хотя. Так что это повод для праздника :)-a
является нестандартным тестовым оператором. Почему бы не использовать-e
? (2) «Невозможно создать временный каталог». является несколько вводящим в заблуждение сообщением об ошибке. (3) Почему бы просто не использоватьmktemp -d
? (4) Вы должны проверить статусы выхода. Например, вы должны сказать! mkdir "$FOLDER" && echo "Unable to create temporary directory." && return 1
илиmkdir "$FOLDER" || { echo "Unable to create temporary directory."; return 1;}
. Аналогично дляcp
иrename
(и, может быть, дажеpushd
, если вы хотите быть осторожным). … (Продолжение)$@
; скажем"$@"
. (5b) Нет необходимости использовать{
и}
когда вы ссылаетесь на переменные так, как вы делаете ("${FOLDER}"
,"${PATTERN}"
и"${file}"
); просто делай"$FOLDER"
,"$PATTERN"
и"$file"
. (6) Предполагается, что файлы находятся в текущем каталоге.cps 's/$/.bak/' d/foo
скопируетd/foo
кfoo.bak
в текущем каталоге, а неd/foo.bak
.Самое близкое, что вы, вероятно, получите к парадигме DOS
mcp
(изmmv
пакета):Если
zsh
доступно, егоzmv
добавленный модуль, возможно, немного ближе:Я бы избегал
ls
- вариант вашего собственного ответа, который безопасен для пробелов (включая переводы строк), будетили возможно
источник
mmv
что это пакет, но в комментариях вы говорите, что команда есть,mcp
но затем в используемой вами команде,mmv
которая также является командой вmmv
пакете. Мне нравится направлениеprintf
примеров, и в отточенном сценарии я бы гарантировал, что 1 и 2 доллара были переданы. +1 для того, чтобы получить катящийся шар :)mcp
это просто синоним дляmmv -c
printf
команды, которой я никогда не пользовался. Вы говорите,printf '%s\0' "$1"*
будет работать, еслиgmail-meta3
был передан в качестве параметра 1?cps gmail-meta3*
написатьprintf '%s\0
«$ @» | пока ... `в функции. Или просто используйтеfor f; do cp -- "$f" "$f.bak"; done
(как ответ Xiota , но как функцию)zmv
вами можно использовать режим «подстановки подстановочных знаков», который, как мне кажется, немного проще:zmv -W -C 'gmail-meta3*' '*.bak'
rsync только решение
Если вы просто хотите сделать резервную копию своих файлов, вы можете скопировать их в новый каталог
rsync /path/to/dir/Filename* /path/to/backupdirectory
Это скопирует
Filename
файлы из/path/to/dir/
в/path/to/backupdirectory
.rsync + имя файла
Если вы хотите, чтобы у ваших файлов резервных копий был суффикс, все становится на свои места
rsync
...rsync -Iu /path/to/dir/Filename* /path/to/dir/Filename* -b --backup-dir=/path/to/backupdirectory --suffix=.bak
Это перезапишет существующие файлы ... существующими файлами (
-I
), но только если они (-u
) новее (а они не являются) и создадут резервную копию с суффиксом.Вы также можете сделать это в том же каталоге. Но лучше исключить существующие резервные копии.
rsync -Iu /path/to/dir/Filename* /path/to/dir/Filename* -b --backup-dir=/path/to/backupdirectory --suffix=.bak --exclude '*.bak'
источник
rsycnc
так что я проголосовал, но, более простой метод был бы,cp Filename* /path/to/backup/dir
потому что файлы не нуждались*.bak
бы в uniquifier, если бы они были в отдельном каталоге.Это следует сделать в соответствии с просьбой:
Использование:
Я выбрал,
?
потому что#
должен быть заключен в кавычки, когда это первый символ шаблона, иначе он распознается как начало комментария.Тестовое задание:
Некоторые более ранние версии скрипта для добавления суффикса:
Похоже на ответ @ WinEunuuchs2Unix, но я думаю, что более гибкий, а не синтаксический анализ
ls
:Поместите это в свой
.bashrc
.Использование:
Альтернатива, с суффиксом в качестве последнего аргумента ( через и через ):
Использование:
источник
copy gmail-meta3* old-meta3*
. В своем ответе я не мог понять, как попасть*
в имя пункта назначения, как мой вопрос ...*
интерпретируется оболочкой, поэтому функция не будет об этом знать. Вам понадобится какой-нибудь другой символ или кавычка, а затем замените его исходным именем файла внутри функции.#
может быть использован в качестве замены подстановочного знака для*
? Чтобы вы могли печататьcopy filenames# save-#
. Я думаю, вы хотите, чтобы подстановочный знак был одинаковым для источника и цели.Я написал эту строку в мой
~/.bashrc
.find
Полагаю, гораздо лучшие ответы с помощью можно выложить. Еще лучше ответы могут быть написаны на языке C. Надеюсь, этот Q & A заставляет шарик катиться за лучшие ответы:for f in "$1"*; do
:$1
этоgmail-meta3
параметр иf
список совпадающих файлов. В сочетании это означает, что gmail-meta3, gmail-meta3-LAB-9999 и т. Д. Делают следующее[[ ! "$f" == *"$2" ]] &&
:$f
такой же, какf
указано выше.$2
это.bak
переданный параметр. В сочетании это означает, что если имя файла не заканчивается.bak
(потому что мы не хотим копировать.bak
и создавать.bak.bak
), то сделайте следующееcp -a "$f" "$f$2";
скопируйте gmail-meta3 в gmail-meta3.bak и т. д.done
: вернуться назад и захватить следующее имя файла вgmail-meta3
* списке.cps gmail-meta3 .bak
Пример выводаИспользуя вопрос в качестве примера, вот как это выглядит в действии:
Примечание. При этом используется
-a
флаг сcp
командой для сохранения временных отметок и лучшего понимания ваших резервных копий файлов.Обратите внимание, что копии файлов имеют ту же дату и время, что и оригиналы. Если
-a
параметр не указан, им будут даны текущая дата и время, и он не будет выглядеть как настоящая резервная копия, за исключением того, что размер файла будет таким же.источник
ls
find
я предполагаю, что вы знаете об опасностях разбораls
? Но в вашем случае в этом нет необходимости: просто сделайтеfor file in "$1"*; do copy -a "$file" "$file$2"; done
это - это абсолютно безопасно и намного проще, чем любое косвенное обращение черезls
илиfind
иwhile
цикл.Еще один способ выполнить ваше требование - скопировать файлы во временный каталог и использовать
rename
команду для их переименования.Если вам нужен сценарий, вы можете использовать его так
И вы можете использовать это так:
Это пример
источник