Скопировать группу файлов (Имя файла *) в резервную копию (Имя файла * .bak)

Фон

В Linux вы можете:

  • Вывести список файлов с помощью ls Filename*
  • Удалить группу файлов с помощью rm Filename*
  • Переместите группу файлов с помощью mv Filename* /New/Directory
  • Но вы не можете скопировать группу файлов с помощью: cp Filename* *.bak

Изменить Linux cp команда для копирования группы файлов

У меня есть группа файлов, которые я хотел бы скопировать, не вводя имена по одному и используя команду 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-*
12
задан 26 June 2019 в 14:50

8 ответов

Вы можете использовать find:

find . -max-depth 1 -name 'gmail-meta3*' -exec cp "{}" "{}.bak" \;

. Он найдет в текущем каталоге . все файлы с именем, совпадающим с шаблоном glob (обратите внимание на одинарные кавычки вокруг шаблона, чтобы предотвратить слипание оболочки ). Для каждого найденного файла он будет выполнять cp от имени к имени. \; в конце гарантирует, что он будет делать каждый файл отдельно, а не передавать их все сразу. Максимальная глубина, равная 1, выполняет поиск только в текущем каталоге, а не в обратном направлении.

12
ответ дан 26 June 2019 в 14:50

Еще один способ выполнить ваше требование - скопировать файлы во временный каталог и использовать команду rename для их переименования.

$ mkdir backup
$ cp filename* /tmp/rename-backup/
$ rename 's/(filename.*)/$1.bak/' /tmp/rename-backup/*
$ mv /tmp/rename-backup/* ./

Если вам нужен сценарий, вы можете использовать его примерно так

cps () {
    mkdir -p /tmp/rename-backup/
    cp "$1"* /tmp/rename-backup/
    rename "s/($1.*)/\$1.$2/" /tmp/rename-backup/*
    mv "/tmp/rename-backup/$1"*".$2" .
}

И можете использовать его так:

cps file bak

Это пример

$ ls -l
total 0
-rw-r--r--  1 danny  danny  0 Jun 26 16:23 file a
-rw-r--r--  1 danny  danny  0 Jun 26 16:23 file ab
-rw-r--r--  1 danny  danny  0 Jun 26 16:23 file ac
-rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename1
-rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename2
-rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename3
-rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename4
$ cps file bak
$ ls -l
total 0
-rw-r--r--  1 danny  danny  0 Jun 26 16:23 file a
-rw-r--r--  1 danny  danny  0 Jun 26 16:41 file a.bak
-rw-r--r--  1 danny  danny  0 Jun 26 16:23 file ab
-rw-r--r--  1 danny  danny  0 Jun 26 16:41 file ab.bak
-rw-r--r--  1 danny  danny  0 Jun 26 16:23 file ac
-rw-r--r--  1 danny  danny  0 Jun 26 16:41 file ac.bak
-rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename1
-rw-r--r--  1 danny  danny  0 Jun 26 16:41 filename1.bak
-rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename2
-rw-r--r--  1 danny  danny  0 Jun 26 16:41 filename2.bak
-rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename3
-rw-r--r--  1 danny  wheel  0 Jun 26 16:41 filename3.bak
-rw-r--r--  1 danny  danny  0 Jun 26 16:05 filename4
-rw-r--r--  1 danny  danny  0 Jun 26 16:41 filename4.bak
2
ответ дан 26 June 2019 в 14:50

rsync only solution

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

rsync /path/to/dir/Filename* /path/to/backupdirectory

Это скопирует файлы Filename из /path/to/dir/ в /path/to/backupdirectory.


rsync + filerename

Если вы хотите, чтобы у ваших файлов резервных копий был суффикс, все становится хакерским с 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'

5
ответ дан 26 June 2019 в 14:50

Ближайшая парадигма DOS, которую вы, скорее всего, получите, - mcp (из пакета mmv):

mcp 'gmail-meta3*' 'gmail-meta3#1.bak'

Если доступно zsh, его добавленный модуль zmv, возможно, немного ближе:

autoload -U zmv

zmv -C '(gmail-meta3*)' '$1.bak'

Я бы избегал ls вне зависимости - вариант вашего собственного ответа , который безопасен для пробелов (включая переводы строк), будет

printf '%s\0' gmail-meta3* | while IFS= read -r -d '' f; do cp -a -- "$f" "$f.bak"; done

или, возможно,

printf '%s\0' gmail-meta3* | xargs -0 -I{} cp -a -- {} {}.bak
6
ответ дан 26 June 2019 в 14:50

Это следует сделать в соответствии с просьбой:

cps(){ p="${@: -1}"; for f in "${@:1:$#-1}"; do cp -ai "$f" "${p//\?/$f}"; done  }

Использование:

cps FILES... pattern
Example 1: cps gmail-meta3* ?.bak
Example 2: cps * save-?
Example 3: cps * bla-?-blubb

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

Тест:

$ touch 'test};{bla#?"blubb'
$ cps test* bla-?-blubb
$ ls
test};{bla#?"blubb  bla-test};{bla#?"blubb-blubb


Некоторые более ранние версии скрипта для добавления суффикса:

Похоже на ответ @ WinEunuuchs2Unix, но я считаю более гибким и не разбирает ls :

cps(){ S="$1"; shift; printf '%s\0' "$@" | xargs -0 -I{} cp -abfS "$S" {} {}; }

Поместите это в свой .bashrc.

Использование:

cps SUFFIX FILES...
Example: cps .bak gmail-meta3*

Альтернатива, с суффиксом в качестве последнего аргумента ( через и через ):

cps(){ S="${@: -1}"; printf '%s\0' "${@:1:$#-1}" | xargs -0 -I{} cp -abfS "$S" {} {}; }

Использование:

cps FILES... SUFFIX
Example: cps gmail-meta3* .bak
<час>
4
ответ дан 26 June 2019 в 14:50

Вы можете использовать петлю for с bash . Как правило, я просто набрал бы его как однострочное, потому что это не та задача, которую я часто выполняю:

for f in test* ; do cp -a "$f" "prefix-${f}.ext" ; done

Однако, если вам нужно это как скрипт:

cps() {
   [ $# -lt 2 ] && echo "Usage: cps REGEXP FILES..." && return 1

   PATTERN="$1" ; shift

   for file in "$@" ; do
      file_dirname=`dirname "$file"`
      file_name=`basename "$file"`
      file_newname=`echo "$file_name" | sed "$PATTERN"`

      if [[ -f "$file" ]] && [[ ! -e "${file_dirname}/${file_newname}" ]] ; then
         cp -a "$file" "${file_dirname}/${file_newname}"
      else
         echo "Error: $file -> ${file_dirname}/${file_newname}"
      fi
   done
}

Использование аналогично rename. Для проверки:

pushd /tmp
mkdir tmp2
touch tmp2/test{001..100}     # create test files
ls tmp2
cps 's@^@prefix-@ ; s@$@.bak@' tmp2/test*    # create backups
cps 's@$@.bak@' tmp2/test*    # more backups ... will display errors
ls tmp2
\rm -r tmp2                   # cleanup
popd
11
ответ дан 26 June 2019 в 14:50

Я написал эту однострочную в мой ~/.bashrc. Полагаю, гораздо лучшие ответы с использованием find можно опубликовать. Еще лучшие ответы могут быть написаны на языке C. Надеюсь, что этот Q & amp; A заставляет шарик катиться за лучшие ответы:

cps () {
    # cps "Copy Splat", copy group of files to backup, ie "cps Filename .bak"
    # Copies Filename1 to Filename1.bak, Filename2 to Filename2.bak, etc.
    # If Filename1.bak exists, don't copy it to Filename1.bak.bak
    for f in "$1"*; do [[ ! "$f" == *"$2" ]] && cp -a "$f" "$f$2"; done

    # OLD version comments suggested to remove 
    # ls "$1"* | while read varname; do cp -a "$varname" "$varname$2"; done
}
  • 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 Пример выходных данных

Используя вопрос в качестве примера, вот как он выглядит в действии:

───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/gmail$ ll gmail-meta3*
-rw-rw-r-- 1 rick rick 26467821 May 20 16:43 gmail-meta3
-rw-rw-r-- 1 rick rick 26467821 May 20 16:43 gmail-meta3.bak
-rw-rw-r-- 1 rick rick      643 May 20 16:43 gmail-meta3-LAB-1558392194-26467821
-rw-rw-r-- 1 rick rick      643 May 20 16:43 gmail-meta3-LAB-1558392194-26467821.bak
-rw-rw-r-- 1 rick rick    49607 May 20 16:44 gmail-meta3-REC-1558392194-26467821
-rw-rw-r-- 1 rick rick    49607 May 20 16:44 gmail-meta3-REC-1558392194-26467821.bak
-rw-rw-r-- 1 rick rick   728954 Jun 27 17:04 gmail-meta3-YAD-1558392194-26467821
-rw-rw-r-- 1 rick rick   728954 Jun 27 05:46 gmail-meta3-YAD-1558392194-26467821.bak
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/gmail$ cps gmail-meta3 .bak
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/gmail$ ll gmail-meta3*
-rw-rw-r-- 1 rick rick 26467821 May 20 16:43 gmail-meta3
-rw-rw-r-- 1 rick rick 26467821 May 20 16:43 gmail-meta3.bak
-rw-rw-r-- 1 rick rick      643 May 20 16:43 gmail-meta3-LAB-1558392194-26467821
-rw-rw-r-- 1 rick rick      643 May 20 16:43 gmail-meta3-LAB-1558392194-26467821.bak
-rw-rw-r-- 1 rick rick    49607 May 20 16:44 gmail-meta3-REC-1558392194-26467821
-rw-rw-r-- 1 rick rick    49607 May 20 16:44 gmail-meta3-REC-1558392194-26467821.bak
-rw-rw-r-- 1 rick rick   728954 Jun 27 17:04 gmail-meta3-YAD-1558392194-26467821
-rw-rw-r-- 1 rick rick   728954 Jun 27 17:04 gmail-meta3-YAD-1558392194-26467821.bak
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/gmail$ 

Примечание: При этом используется флаг -a с командой cp для сохранения временных отметок и лучшего понимания ваших резервных копий файлов.

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

4
ответ дан 26 June 2019 в 14:50

Вот пример одного нетипичного использования sed, применимого для этой задачи:

sed -i.bak '' file-prefix*

Таким образом, фактически, sed не будет изменять файлы, потому что мы не не предоставил никаких команд '', но благодаря опции -i[suffix] он создаст резервную копию каждого файла. Я нашел этот подход, когда искал Есть ли способ создать резервную копию файла, не вводя его имя дважды?

12
ответ дан 26 June 2019 в 14:50

Другие вопросы по тегам:

Похожие вопросы: