создание архива с использованием tar, включая все 'точечные файлы', но исключая все подкаталоги и структуру каталогов / wo

18

Я хочу сделать резервную копию всех 'точечных файлов' (например, .zshrc) в моем домашнем каталоге с помощью tar , но исключая структуру каталогов и все подкаталоги.

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

#!/bin/zsh
BACKUPFILE=dotfile_backup.tar.gz
tar --create --file=$HOME/$BACKUPFILE --auto-compress --no-recursion --exclude=. --exclude=.. --exclude=*/ --directory=$HOME .*

Я также думал об использовании findи передаче результата в tar, но безуспешно. Кто-нибудь знает, как решить эту, казалось бы, легкую задачу?

PS: Большую часть времени, когда я использую tar для создания архива, мне приходится думать о комиксе xkcd:

XKCD 1168 :)

klingt.net
источник
Ответ сима работает, но если кто-то получил регулярное выражение, которое соответствует только скрытым файлам, пожалуйста, опубликуйте его!
klingt.net
1
Конечно, это будет лучше достигнуто с вашей оболочкой. Я понимаю, что у zsh есть глобусы, которые выбирают только файлы - *(.)и я думаю, что он исключает .и ..из .*по умолчанию (и они не будут выбраны в .*(.)любом случае, так как он выбирает только файлы). Я сам не пользуюсь zsh, поэтому я не уверен, чтобы превратить это в ответ.
evilsoup

Ответы:

14

Вы можете использовать эту команду для резервного копирования всех ваших dotfiles ( .<something>) в вашем $HOMEкаталоге:

$ cd ~
$ find . -maxdepth 1 -type f -name ".*" -exec tar zcvf dotfiles.tar.gz {} +

регулярное выражение, используя только tar?

метод № 1

Я исследовал это совсем немного и пришел пустой. Ограничивающим фактором будет то, что при tarвыполнении исключений завершающий слеш ( /), который отображается с каталогами, не является частью уравнения, когда tar выполняет сопоставление с образцом.

Вот пример:

$ tar -v --create --file=do.tar.gz --auto-compress --no-recursion --exclude={'.','..','.*/'} .*
.qalculate/
.qt/
.qterm/
.qtoctave/
.RapidSVN
.RData
.Rhistory

Этот вариант включает в себя исключение, .*/и вы можете видеть с включенным в tar подробным переключателем -v, что эти каталоги проходят через это исключение.

метод № 2

Я подумал, что, может быть, переключатели --no-wildcards-match-slashили --wildcards-match-slashослабит жадность, .*/но это тоже не имело никакого эффекта.

Удаление косой черты из исключения также .*не было возможным, поскольку это tarуказывало бы на исключение всех файлов точек и каталогов точек:

$ tar -v --create --file=do.tar.gz --auto-compress --no-recursion --exclude={'.','..','.*'} .*
$

Метод № 3 (Гадкий!)

Поэтому единственная альтернатива, которую я могу придумать, - предоставить список файлов tar. Что-то вроде этого:

$ tar -v --create --file=do.tar.gz --auto-compress --no-recursion --wildcards-match-slash --exclude={'.','..','.*/'} $(ls -aF | grep -E "^\..*[^/]$")
.RapidSVN
.RData
.Rhistory

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

так что мы узнали?

Кажется, нет простого и элегантного способа добиться этого, используя tar& регулярные выражения. Что касается комментария @ terdon, find ... | tar ...это действительно более подходящий способ сделать это.

SLM
источник
Я действительно хотел покончить с этим regex, но я должен был знать, что так не получится :)
klingt.net
@ klingt.net - это должно быть возможно, я смотрю сейчас.
SLM
@ klingt.net почему вы предпочитаете более сложный способ? При использовании regexвам, вероятно, потребуется экранировать ведущую точку, и вам будет трудно игнорировать .и ... Я уверен, что это возможно, так как slm, вероятно, продемонстрирует, но я не понимаю, почему это будет стоить.
Terdon
1
@ klingt.net - все, что findнаходит команда, передается в качестве аргумента tar. The {}говорит, где вы хотите, чтобы эти результаты были в соответствующей -execкоманде. Команда +говорит добавить столько результатов, findсколько поместится в командной строке, и вызывать tarтолько пару раз, а не каждый раз, когда найден результат.
SLM
1
@ klingt.net - нет способа сделать это с помощью regexи tarпотому что нет способа изолировать точечные каталоги ( .blah/). Tar не использует завершающий слеш при исключении.
SLM
4

Этот вид контроля над соответствующими файлами находится вне зоны комфорта tar. Его правила сопоставления файлов ограничены простыми совпадениями по именам.

find Это один из способов, но поскольку у вас есть Zsh, вам будет проще:

tar -cf "$HOME/$BACKUPFILE" --auto-compress .*(.)

То, что .в скобках в конце подстановочного выражения есть глобальный квалификатор, который говорит «только сопоставлять обычные файлы».

Символьные ссылки на обычные файлы не совпадают. Если вы измените на .*(-.), они будут включены, но файл не попадет в архив, если он также не включен. Если вы хотите заменить символическую ссылку на их цели, сделайте это .*(-.:A):Aдобавляет модификатор расширения истории, который разрешает все символические ссылки в пути, который не использует символические ссылки.

Жиль "ТАК - прекрати быть злым"
источник
3

Этот ответ основан на slm, но я также покажу вам, как включать каталоги, начинающиеся с .

Чтобы сжать точечные файлы в вашем домашнем каталоге:

$ cd
$ find . -maxdepth 1 -type f -name ".?*" -exec tar czfv dotfiles.tgz {} +

Чтобы включить каталоги:

$ find . -maxdepth 1 -name ".?*" -exec tar czfv dotfiles.tgz {} +

Опция ?необязательна в первой команде, но не во второй, иначе findбудет включать .(текущий) каталог.

sudoman
источник
1

как насчет:

tar -C $HOME -cvzf dotfiles.tgz .
аноним
источник