Вопрос или проблема
Я хочу обновить tar-файл с частью измененного содержимого, перезаписав оригинальный файл, в скрипте.
Я пробовал tar -u
, -A
и -r
, но ни один из них не делает то, что я хочу. Я также попробовал с --overwrite
.
Простой тест:
cd ~
mkdir test
echo foo > test1.txt
mkdir test_dir
cd test_dir
echo bar > test2.txt
cd ../..
tar cvf test.tar test
tar tvf test.tar # проверить содержимое
echo barbarbar >> test/test_dir/test2.txt
tar rvf test.jar test # или Avf, или uvf, это то же самое: измененный файл не перезаписывает оригинальный файл в tar
-u --overwrite
теоретически будет “обновлять”, но фактически только добавляет и не добавляет измененный файл, поэтому я вижу дваtest1.txt
и одинtest2.txt
в tar, сtest2.txt
, который является старым-A --overwrite
теоретически будет добавлять, но возвращает ошибку:tar: test: Read error at byte 0, while reading 1024 bytes: Is a directory tar: Error is not recoverable: exiting now
-r --overwrite
теоретически будет “добавлять”, но только добавляет, и не перезаписывает, поэтому я вижу дваtest1.txt
и дваtest2.txt
в tar.
Я подумал: ОК, тогда tar не включает возможность обновления tar на месте. Но потом я вспомнил, что это можно легко сделать, перетащив новую папку в tar файл в Gnome (думаю, это обрабатывается “Менеджером архивов”), так что это, по крайней мере, возможно.
Как я могу перезаписывать файлы в tar с помощью командной строки/скрипта?
Вы можете создать скрипт, который создаст другой tar-архив вместо обновления оригинала, а затем удалить оригинал и переименовать новый в оригинал…
вероятно, так “менеджер архивов” выполняет это более продвинутым способом, и я бы не стал пытаться имитировать такое поведение в bash, но это не значит, что вы не должны пытаться…
Я нашел этот абзац в документации GNU tar
, так что перезапись не поддерживается tar
, возможно, потому что в старые времена tar
был задуман как симуляция архивирования на ленту, и не думал о замене файла, так как это не разрешено на физической ленте.
Я удалю оригинальный файл из tar и добавлю измененный.
https://www.gnu.org/software/tar/manual/html_node/how-to-update.html#how-to-update
4.2.3.1 Как обновить архив, используя ‘–update’
Вы должны использовать аргументы имени файла с операцией ‘–update’ (‘-u’). Если вы не указываете никаких файлов, tar не будет действовать ни для каких файлов и не скажет вам, что он ничего не сделал (что может заставить вас запутаться).
Чтобы увидеть работу опции ‘–update’, создайте новый файл ‘classical’ в вашей практике директории и добавьте немного текста в файл ‘blues’, используя любой текстовый редактор. Затем вызовите tar с операцией ‘update’ и указанием опции ‘–verbose’ (‘-v’), используя имена всех файлов в директории ‘practice’ в качестве аргументов имени файла:
$ tar --update -v -f collection.tar blues folk rock classical blues classical $
Поскольку мы указали режим подробного вывода, tar распечатывает имена файлов, над которыми он работает, иными словами, это имена файлов, которые нуждаются в обновлении. Если вы выполните ‘tar –list’ и посмотрите на архив, вы увидите ‘blues’ и ‘classical’ в его конце. Всего будет две версии элемента ‘blues’; та, что в конце, будет новее и больше, так как вы добавили текст перед его обновлением.
Причина, по которой tar не перезаписывает старый файл при обновлении, заключается в том, что запись в середину секции ленты — сложный процесс. Ленты не предназначены для перемещения назад. См. раздел Ленты и другие архивные носители, для получения дополнительной информации о лентах.
РЕДАКТИРОВАНИЕ:
--delete
не работает/очень медленно. Кажется, что удаление файлов из tar не очень осуществимо, возможно, по замыслу. Думаю, мне нужно извлечь/удалить/упаковать заново, или: https://unix.stackexchange.com/questions/68732/remove-files-from-tar-archive, но я пока не знаю как.
Ответ или решение
Обновление архива tar с заменой существующих файлов — это задача, которая часто вызывает путаницу среди пользователей, особенно учитывая принципы работы tar, сформированные в эпоху лент и аналогичных систем хранения данных. Для того чтобы понять, почему GNU tar ведет себя именно так, и какие действия возможно предпринять для достижения необходимого результата, нужно рассмотреть теорию, примеры и практическое применение возможных решений.
Теория
GNU tar, истоки которого связаны с лентами, предназначен в первую очередь для линейного потока данных. На лентах невозможно перемещаться назад и заменять данные посредине, что объясняет отсутствие возможности простого перезаписывания файлов в архивах tar. В связи с этим, при использовании команды tar -u
или tar -r
, файлы просто добавляются в конец архива, а не заменяют существующие версии.
Основной целью команды tar
является создание, извлечение и добавление файлов к архивам, а не их учётное обновление. Это накладывает ограничения на обновление существующих данных и требует от пользователя ухищрений, если необходимо добиться обновления с заменой.
Ограничения tar
:
-
Линейное добавление: команды
-u
и-r
добавляют файлы в конец архива, что оставляет старые версии доступными, а новые просто добавляются. -
Отсутствие встроенного удаления: несмотря на наличие команды
--delete
, она неэффективна для больших архивов, так как требует создание временной копии архива без удаляемых файлов. -
Обратная совместимость с лентами: основная концепция работы с архивами tar заключается в обратной совместимости с магнитными лентами, что делает процесс записи на середину архива невозможным.
Пример
Допустим, у нас есть архив test.tar
, содержащий файлы в определенной директории. Этапы изменения файла test2.txt
в архиве можно начать с изменения самого файла на диске:
cd ~/test
echo "новое содержимое" > test_dir/test2.txt
Теперь контент файла на диске изменен, но в архиве остается старая версия, что видно при выполнении команды:
tar tvf test.tar
Использование команд tar -u
или tar -r
приведет только к добавлению нового файла в конец архива, не затрагивая старые версии. Несмотря на существование команды --delete
, её малопроизводительность делает её непрактичной для больших архивов.
Применение
Как же достичь необходимого обновления файлов в архиве tar без дублирования? Самый практичный способ — это извлечение, обновление и пересоздание архива. При этом ваши действия будут аналогичны тем, которые выполняет графическая утилита как Gnome Archive Manager.
Практическое решение:
-
Извлечение текущего архива:
mkdir /tmp/extracted tar xvf test.tar -C /tmp/extracted
-
Замена необходимых файлов: обновите или замените файлы в
/tmp/extracted
с теми, что содержатся в вашей директорииtest
. -
Пересоздание архива:
tar cvf new_test.tar -C /tmp/extracted .
-
Замена старого архива:
mv new_test.tar test.tar
Таким образом, вы создаете новый архив, который полностью учитывает обновления без излишнего дублирования информации.
Вывод
Механизм работы GNU tar, хотя и имеет свои ограничения, объясняется историческим наследием и техническими аспектами работы с потоками данных. Для работы с архивами в командной строке с обновлением содержимого и заменой старых файлов требуется использование извлечения и пересоздания архива. Этот метод может показаться громоздким, но гарантирует полное соответствие обновленного архива вашим ожиданиям.
Если же подобный подход слишком затратен по времени или ресурсам для вашего сценария, могут быть полезны альтернативные архиваторы, такие как zip
или 7z
, которые предлагают больше гибкости в редактировании архива за счет частично рандомизированного доступа к его содержимому.