tar: файл змінено під час читання


78

Я використовую makeі tarдля резервного копіювання. Під час виконання make-файлу відображається команда tar file changed as we read it. В цьому випадку,

  • пакунок tar в порядку, коли з’являється попередження
  • але він зупиняє команду tar для наступного резервного копіювання
  • файл, що відображає попередження, насправді не змінюється - це дійсно дивно, що попередження з’являється
  • файли, що відображають попередження, з’являються випадковим чином, я маю на увазі, що кожного разу, коли я запускаю свій make-файл, файли, що відображають попередження, відрізняються
  • --ignore-failed-readне допомагає. Я використовую tar 1.23 у MinGW
  • Я щойно змінив комп’ютер на 64-розрядний WIN7. Сценарій добре працює у старому 32-розрядному WIN7. Але версія tar не така нова, як 1.23.

Як я можу зупинити попередження tar, щоб зупинити резервне копіювання після попередження?


Edit-2 : це може бути причиною

Як я вже говорив вище, сценарій оболонки bash добре працював на моєму старому комп'ютері. У порівнянні зі старим комп'ютером msysверсія інша. Так само як і версія команди tar. У старому комп’ютері tar - 1.13.19, а в новому - 1.23. Я скопіював стару команду tar, не скопіювавши її залежність msys-1.0.dll на новий комп'ютер, і перейменував її у tar_old. І я також оновив команду tar у сценарії оболонки та запустив сценарій. Тоді все ок. Отже, здавалося, що проблема в команді tar. Я впевнений, що жодного файлу не було змінено під час тарування. Це помилка для команди tar в новій версії? Не знаю.


Редагувати-1 : додати більше деталей

Резервне копіювання викликається сценарієм оболонки bash. Він сканує цільовий каталог і будує makefile, а потім викликає make для використання команди tar для резервного копіювання. Далі йде типовий make-файл, побудований сценарієм оболонки bash.

#--------------------------------------------
# backup VC
#--------------------------------------------
# the program for packing
PACK_TOOL=tar

# the option for packing tool
PACK_OPTION=cjvf

# M$: C driver
WIN_C_DIR=c:

# M$: D driver
WIN_D_DIR=d:

# M$: where the software is
WIN_PRG_DIR=wuyu/tools
# WIN_PRG_DIR=

# where to save the backup files
BAKDIR=/home/Wu.Y/MS_bak_MSYS

VC_FRAMEWORK=/home/Wu.Y/MS_bak_MSYS/tools/VC/VC_framework.tar.bz2
VC_2010=/home/Wu.Y/MS_bak_MSYS/tools/VC/VC_2010.tar.bz2

.PHONY: all

all: $(VC_FRAMEWORK) $(VC_2010)

$(VC_FRAMEWORK): $(WIN_C_DIR)/$(WIN_PRG_DIR)/VC/Framework/*
    @$(PACK_TOOL) $(PACK_OPTION) "$@" --ignore-failed-read /c/$(WIN_PRG_DIR)/VC/Framework
$(VC_2010): $(WIN_C_DIR)/$(WIN_PRG_DIR)/VC/VS2010/*
    @$(PACK_TOOL) $(PACK_OPTION) "$@" --ignore-failed-read /c/$(WIN_PRG_DIR)/VC/VS2010

Як бачите, пакунок tar зберігається в ~ / MS_bak_MSYS / tools / VC / VC_2010.tar.bz2. Я запускаю сценарій в ~ / qqaa. ~/MS_bak_MSYSвиключається з команди tar. Отже, файл tar, який я створюю, не знаходиться всередині каталогу, який я намагаюся вставити у файл tar. Ось чому мені було дивно, що з’явилося попередження.


Схоже, ви використовуєте налаштування Windows, тому для вас це не актуально. Проте ми маємо подібну проблему, коли базовою файловою системою є glusterfs. Схоже, є помилка, коли lstat і fstat повертають різні значення: bugzilla.redhat.com/show_bug.cgi?id=1058526
Ар'є Склярук

Виникла ця проблема за допомогою tar на томі, змонтованому Windows Docker. Обмін tarутилітою на paxпрацював у мене.
Андреас

Відповіді:


79

Я також стикаюся з повідомленнями tar, "зміненими під час читання". Для мене це повідомлення сталося, коли я створював файл tar файлової системи Linux у середовищі побудови bitbake. Ця помилка була спорадичною.

Для мене це сталося не через створення tar-файлу з того самого каталогу. Я припускаю, що насправді є якийсь файл, переписаний або змінений під час створення файлу tar.

Повідомлення є попередженням, і воно все ще створює файл tar. Ми все ще можемо придушити ці попереджувальні повідомлення, встановивши параметр

--warning=no-file-changed

( http://www.gnu.org/software/tar/manual/html_section/warnings.html )

І все-таки повернення коду виходу через tar - "1" у випадку попереджувального повідомлення: http://www.gnu.org/software/tar/manual/html_section/Synopsis.html

Отже, якщо ми викликаємо файл tar з якоїсь функції у сценаріях, ми можемо обробити код виходу приблизно так:

set +e 
tar -czf sample.tar.gz dir1 dir2
exitcode=$?

if [ "$exitcode" != "1" ] && [ "$exitcode" != "0" ]; then
    exit $exitcode
fi
set -e

У мене таке саме питання, і ця відповідь "вирішила" мою проблему, давши мені можливість обійти її. Дякую @sandeep.
jaskho

11
Tar виводиться з 1: "Якщо tar надано опцію` --create ', `--append' або` --update ', цей код виходу означає, що деякі файли були змінені під час архівування, тому отриманий архів не містить точного копія набору файлів. " Це така погана поведінка, що відкидає щелепу - вона вб’є трубопровід, і його неможливо зупинити. facepalm
Отей

Примітка @Otheusset +e
Ryan Brodie

2
@RyanBrodie Я думав про те, як set -o pipefail; tar ... | gzip. Але я беру це назад; це не вб'є весь конвеєр, оскільки вихід відкладено до кінця виконання.
Отей

60

Хоча це дуже пізно, але нещодавно у мене була та сама проблема.

Проблема в тому, що dir .змінюється так, xyz.tar.gzяк створюється після запуску команди. Є два рішення:

Рішення 1: tar не буде заперечувати, якщо архів буде створений у будь-якому каталозі всередині .. Можуть бути причини, чому не вдається створити архів поза робочим простором. Обійшов це, створивши тимчасовий каталог для розміщення архіву як:

mkdir artefacts
tar -zcvf artefacts/archive.tar.gz --exclude=./artefacts .
echo $?
0

Рішення 2: Цей мені подобається. створити файл архіву перед запуском tar:

touch archive.tar.gz
tar --exclude=archive.tar.gz -zcvf archive.tar.gz .
echo $?
0

6
У рішенні 2, просто поставте --exclude=archive.tar.gzперед іншими optiosn, -zvcfі це насправді працює добре.
Кай Кандлер

37

Якщо вам потрібна допомога у налагодженні подібної проблеми, вам потрібно надати правило make або принаймні команду tar, яку ви викликали. Як ми можемо побачити, що не так із командою, якщо немає команди, яку потрібно бачити?

Однак у 99% випадків така помилка означає, що ви створюєте файл tar у каталозі, який ви намагаєтеся вставити у файл tar. Отже, коли tar намагається прочитати каталог, він знаходить файл tar як член каталогу, починає його читати і записує у файл tar, і так між часом, коли він починає читати файл tar, і коли він закінчується читаючи файл tar, файл tar змінився.

Наприклад, щось на зразок:

tar cf ./foo.tar .

Неможливо "зупинити" це, бо це не неправильно. Просто покладіть файл tar де-небудь ще, коли ви його створюєте, або знайдіть інший спосіб (за допомогою --excludeбудь-якого іншого), щоб опустити файл tar.


Я додав більше деталей в оригінальному дописі. Будь ласка, перевірте.
warem

Виходячи з інформації тут, я не знаю, що не так. Однак я дуже мало знаю про роботу з Windows або cygwin ... Я знаю, що з файловою системою Windows набагато складніше працювати з кількома програмами WRT, що мають доступ до одного файлу, ніж з файловою системою на основі POSIX. Але це, здається, не відразу стосується вашої ситуації. Все, що я можу запропонувати, - це видалити @в своїх правилах і вивчити команду, яка робить друк, щоб переконатися, що вона правильна, і подивитися на файли, які намагається створити tar (вихід з параметра v), щоб переконатися, що немає нічого загадкового.
MadScientist

18

Ось однорядковий рядок для ігнорування стану виходу tar, якщо він дорівнює 1. Немає необхідності, set +eяк у сценарії sandeep . Якщо статус виходу tar є 0 або 1, цей одношаровий лайнер повернеться зі статусом виходу 0. В іншому випадку він повернеться зі статусом виходу 1. Це відрізняється від сценарію Sandeep, де початкове значення статусу виходу зберігається, якщо воно відрізняється від 1 .

tar -czf sample.tar.gz dir1 dir2 || [[ $? -eq 1 ]]


5

Для вдосконалення однокласника Фабіана; скажімо, що ми хочемо ігнорувати лише статус виходу 1, але зберегти статус виходу, якщо це щось інше:

tar -czf sample.tar.gz dir1 dir2 || ( export ret=$?; [[ $ret -eq 1 ]] || exit "$ret" )

Це робить все, що робить сценарій Сандіпа, в один рядок.


4

Просто використання зовнішнього каталогу для виводу, вирішило проблему для мене.

sudo tar czf ./../31OCT18.tar.gz ./

1
Якщо покласти новий смол в ту саму папку, яку ти стискаєш, це зміниться, ха-ха
Даніель В.

0

Це спрацювало для мене, додавши простий тайм-аут сну 20 сек. Це може статися, якщо ваш вихідний каталог все ще пише. Отже, присипте, щоб резервне копіювання закінчилося, і тоді смола повинна працювати нормально. Це також допомогло мені отримати правильний статус виходу.

sleep 20
tar -czf ${DB}.${DATE}.tgz ./${DB}.${DATE}

0

Я не впевнений, що це вам підходить, але я помітив, що tarне справляється зі зміненими / видаленими файлами в режимі конвеєра. Подивіться, що я маю на увазі.

Тестовий сценарій:

#!/usr/bin/env bash
set -ex
tar cpf - ./files | aws s3 cp - s3://my-bucket/files.tar
echo $?

Видалення випадкових файлів вручну ...

Вихід:

+ aws s3 cp - s3://my-bucket/files.tar
+ tar cpf - ./files
tar: ./files/default_images: File removed before we read it
tar: ./files: file changed as we read it
+ echo 0
0

1
Це тому, що коди виходу за замовчуванням ігноруються всередині каналів. І це хороша практика, коли їх можна повернути за допомогою "set -o pipefail".
Сергій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.