Вопрос или проблема
Я пытаюсь создать архив, например, archive.tar.gz
, внутри текущего рабочего каталога, например, /builds/project/
, не сохраняя archive.tar.gz
внутри archive.tar.gz
.
Чтобы предотвратить это, я пытаюсь использовать опцию –exclude=PATTERN.
Это должно быть легкой задачей. Но это не так.
Наконец, я хотел бы назвать архив по установленной переменной и исключить его.
Версии:
$ bash --version
GNU bash, version 5.2.15(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
Это бесплатное программное обеспечение; вы свободны изменять и перераспределять его.
Гарантия отсутствует, в пределах, разрешенных законом.
$ tar --version
tar (GNU tar) 1.34
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
Это бесплатное программное обеспечение: вы свободны изменять и перераспределять его.
Гарантия отсутствует, в пределах, разрешенных законом.
Написано Джоном Гилмором и Джеем Фенласоном.
Я перепробовал множество версий, с кавычками, без, исключение на разных позициях, PATTERN с ./ и без, и ничего не работает:
$ tar -czf --exclude=archive1.tar.gz archive1.tar.gz . || true
tar: archive1.tar.gz: Не удается получить информацию: Нет такого файла или каталога
tar: .: файл изменился, пока мы его читали
tar: Завершение с кодом ошибки из-за предыдущих ошибок
$ tar -czf --exclude="archive2.tar.gz" archive2.tar.gz . || true
tar: archive2.tar.gz: Не удается получить информацию: Нет такого файла или каталога
tar: .: файл изменился, пока мы его читали
tar: Завершение с кодом ошибки из-за предыдущих ошибок
$ tar -czf --exclude=./archive3.tar.gz archive3.tar.gz . || true
tar: archive3.tar.gz: Не удается получить информацию: Нет такого файла или каталога
tar (child): --exclude=./archive3.tar.gz: Не удалось открыть: Нет такого файла или каталога
tar (child): Ошибка не восстанавливаема: завершение сейчас
tar: --exclude=./archive3.tar.gz: Не удалось записать: Разрыв трубопровода
tar: Дочерний процесс вернул статус 2
tar: Ошибка не восстанавливаема: завершение сейчас
$ tar -czf --exclude="./archive4.tar.gz" archive4.tar.gz . || true
tar: archive4.tar.gz: Не удается получить информацию: Нет такого файла или каталога
tar (child): --exclude=./archive4.tar.gz: Не удалось открыть: Нет такого файла или каталога
tar (child): Ошибка не восстанавливаема: завершение сейчас
tar: --exclude=./archive4.tar.gz: Не удалось записать: Разрыв трубопровода
tar: Дочерний процесс вернул статус 2
tar: Ошибка не восстанавливаема: завершение сейчас
$ tar -czf archive5.tar.gz --exclude=archive5.tar.gz . || true
tar: .: файл изменился, пока мы его читали
$ tar -czf archive6.tar.gz --exclude="archive6.tar.gz" . || true
tar: .: файл изменился, пока мы его читали
$ tar -czf archive7.tar.gz --exclude=./archive7.tar.gz . || true
tar: .: файл изменился, пока мы его читали
$ tar -czf archive8.tar.gz --exclude="./archive8.tar.gz" . || true
tar: .: файл изменился, пока мы его читали
$ TAR_FILE=archive9.tar.gz ; tar -czf --exclude=$TAR_FILE $TAR_FILE . || true
tar: archive9.tar.gz: Не удается получить информацию: Нет такого файла или каталога
tar: .: файл изменился, пока мы его читали
tar: Завершение с кодом ошибки из-за предыдущих ошибок
$ TAR_FILE=archive10.tar.gz ; tar -czf --exclude="$TAR_FILE" $TAR_FILE . || true
tar: archive10.tar.gz: Не удается получить информацию: Нет такого файла или каталога
tar: .: файл изменился, пока мы его читали
tar: Завершение с кодом ошибки из-за предыдущих ошибок
$ TAR_FILE=archive11.tar.gz ; tar -czf --exclude=./$TAR_FILE $TAR_FILE . || true
tar: archive11.tar.gz: Не удается получить информацию: Нет такого файла или каталога
tar (child): --exclude=./archive11.tar.gz: Не удалось открыть: Нет такого файла или каталога
tar (child): Ошибка не восстанавливаема: завершение сейчас
tar: --exclude=./archive11.tar.gz: Не удалось записать: Разрыв трубопровода
tar: Дочерний процесс вернул статус 2
tar: Ошибка не восстанавливаема: завершение сейчас
$ TAR_FILE=archive12.tar.gz ; tar -czf --exclude="./$TAR_FILE" $TAR_FILE . || true
tar: archive12.tar.gz: Не удается получить информацию: Нет такого файла или каталога
tar (child): --exclude=./archive12.tar.gz: Не удалось открыть: Нет такого файла или каталога
tar (child): Ошибка не восстанавливаема: завершение сейчас
tar: --exclude=./archive12.tar.gz: Не удалось записать: Разрыв трубопровода
tar: Дочерний процесс вернул статус 2
tar: Ошибка не восстанавливаема: завершение сейчас
$ TAR_FILE=archive13.tar.gz ; tar -czf $TAR_FILE --exclude=$TAR_FILE . || true
tar: .: файл изменился, пока мы его читали
$ TAR_FILE=archive14.tar.gz ; tar -czf $TAR_FILE --exclude="$TAR_FILE" . || true
tar: .: файл изменился, пока мы его читали
$ TAR_FILE=archive15.tar.gz ; tar -czf $TAR_FILE --exclude=./$TAR_FILE . || true
tar: .: файл изменился, пока мы его читали
$ TAR_FILE=archive16.tar.gz ; tar -czf $TAR_FILE --exclude="./$TAR_FILE" . || true
tar: .: файл изменился, пока мы его читали
Если использовать аргумент tar f
, он должен быть неотъемлемо связан с именем архива, поэтому вам нужно
tar -czf archive1.tar.gz --exclude=archive1.tar.gz .
Чтобы избежать предупреждения, просто
touch archive1.tar.gz
предварительно создайте пустой файл, чтобы .
не изменился во время создания архива.
Ответ или решение
Создание архива tar.gz в текущем рабочем каталоге, исключая сам архив из его содержимого, может представлять трудности, особенно когда возникает ошибка "файл изменился во время чтения" (file changed as we read it). Эта проблема часто возникает в сценариях сборки, таких как GitLab CI/CD, где динамическое создание файлов может мешать процессу архивирования.
Решение проблемы
Когда вы пытаетесь создать архив, используя команду tar с указанием имени файла архива, система начинает читать и архивировать содержимое текущего каталога. В случае, если вы одновременно создаете архив в этом же каталоге, это может вызвать конфликты, так как файл архива ещё не существует на момент его чтения, что и приводит к возникновению ошибки.
Алгоритм действий
-
Создайте пустой файл архива заранее. Чтобы избежать конфликта, можно создать пустой файл архива перед его использованием в команде tar:
TAR_FILE=archive.tar.gz touch $TAR_FILE
-
Используйте команду tar с правильными параметрами. После этого, когда файл архива будет создан, вы можете использовать команду tar с исключением самого файла архива:
tar -czf $TAR_FILE --exclude=$TAR_FILE .
Пример полного процесса
При использовании GitLab CI/CD этот процесс может выглядеть следующим образом:
job:
script:
- TAR_FILE=archive.tar.gz
- touch $TAR_FILE
- tar -czf $TAR_FILE --exclude=$TAR_FILE .
Объяснение параметров
- -czf: Эта комбинация трактует команды tar как:
c
— создать архивz
— сжать его с использованием gzipf
— указывает имя файла архива
- –exclude: Данный параметр исключает указанный файл из архива. В этом случае мы исключаем $TAR_FILE.
Итог
Убедитесь, что вы выполняете эти шаги в правильном порядке, чтобы избежать ошибок, связанных с изменением файлов в каталоге во время чтения. Это решение позволяет создать архив в текущем рабочем каталоге, исключив сам архив из его содержимого, обеспечивая тем самым корректную работу ваших скриптов и сборок в CI/CD.