Скрипт для преобразования архива .gz в .lzma с сохранением времени изменения/создания файла и прав доступа, а также с минимальным влиянием на производительность.
Для переименования группы файлов можно использовать конструкцию вида:find . -name "*.gz" -print0 | xargs -0 -n 1 echo ~/bin/gz2lzma.sh | batch
gz2lzma.sh:
#!/bin/sh
#
# CopyLeft (L) john_erohin, 2022
#
# gz2lzma.sh: convert .gz to .lzma with same mtime, ctime and access rights
#
# in: $1 = file name with or without ".gz" suffix
# out: file "$1.lzma" and removed "$1.gz" if conversion is ok
#
# warining: if $1.lzma exist, it will be silently overwritten
#
# use someth like
# find . -name "*.gz" -print0 | xargs -0 -n 1 echo ~/bin/gz2lzma.sh | batch
# for mass background conversion
#
F=$1
F=`echo $F | sed -e s:\.gz\$::g`if [ -f $F.gz ] ; then
/usr/bin/eatmydata -- \
/usr/bin/nice -19 \
/usr/bin/chrt --idle 0 \
/usr/bin/ionice -c 3 \
gzip -t $F.gz > /dev/null 2>&1
RC=$?
if [ $RC -ge 1 ]; then
echo error $RC in $F.gz : integrity test failed
exit $RC
fi
CTIME=`stat -c %w $F.gz`
MTIME=`stat -c %y $F.gz`
CHMOD=`stat -c %a $F.gz`
TF=`mktemp`
T=`basename $TF`
rm $TF
L=$F.$T.lzma
touch $L
chmod $CHMOD $L
gzip -cdk $F.gz | \
/usr/bin/eatmydata -- \
/usr/bin/nice -19 \
/usr/bin/chrt --idle 0 \
/usr/bin/ionice -c 3 \
/usr/bin/lzma -z9c > $L
RC=$?
if [ $RC -eq 0 ]; then
touch --date="$CTIME" $L
touch -m --date="$MTIME" $L
mv $L $F.lzma
rm $F.gz
else
echo lzma run-time error $RC processing $L
exit $RC
fi
else
echo error: no input file $F or $F.gz
exit 1
fi
URL:
Обсуждается: http://www.opennet.me/tips/info/3202.shtml
Привер того, как нельзя делать: переменные без кавычек, вызов внешних программ с простой передачей им "голых" переменных (которые подставляются в exec), двойное раскодирование (сперва "тест", потом основное) вместо обработки кодов возврата...
Корявый скрипт новичка.
соглашусь с предыдущим оратором. Автор, вбей свой скрипт в shellcheck.> Скрипт для конвертации архива gz в lzma
что за задачка такая странная? Зачем это вообще нужно?
> echo
printf
> if условие; then
> практически весь скрипт
> else
> какой-то однострочный пустяк
> fiпросто проверь в самом начале на плохое условие и сделай ранний выход. Зачем весь скрипт помещать внутрь гигантского ифа?
> /usr/bin
не понимать, зачем универсальному кросс-дистровому скрипту хардкодить пути к бинарям. А если я захочу переопределить $PATH?
> CopyLeft (L)
Что за лицензия такая?
> echo error: no input file $F or $F.gz
> exit 1почему ошибки идут в stdout, а не в stderr?
где стандартная преамбула, врубающая строгий режим? типа
set -euo pipefail
shopt -s inherit_errexitпочему у переменных однобуквенные названия? да ты и сам спустя месяц забудешь, что они значат
> if [ -f $F.gz ]
че за бред, это не единственная IO-ошибка, которая может возникнуть. Об этих ошибках должна рапортовать вызываемая прога, а твое дело -- просто вовремя выходить и не глушить ее stdout/err.
> set -euo pipefail
> shopt -s inherit_errexitтам в шебанге -- `/bin/sh`, нет никакого pipefail.
какой такой шопт? его тоже нет.
> там в шебанге -- `/bin/sh`, нет никакого pipefail.однако "set -e" есть.
> какой такой шопт? его тоже нет.
есть такие потребители смузей, что линкуют жырный bash на /bin/sh
Не знаю, как в gentoo, но в calculate по дефолту. А может и в gentoo тоже.
> есть такие потребители смузей, что линкуют жырный bash на /bin/shА ещё у bash конвейеры передают быстрее, чем (внезапно) тот же dash, сам мерял.
Пытаться сделать что-то с POSIX-шеллом сложнее hello world — бесполезная трата времени.Писать на баше это разумный и оптимальный подход, за исключением 3½ вырожденных случаев, которые ты за свою жизнь в дикой природе не встретишь, а если встретишь, то и там тоже будет баш.
> Пытаться сделать что-то с POSIX-шеллом сложнее hello world — бесполезная трата времени.на чистом /bin/sh - да, возможно.
но зачем, если есть grep, sed и awk.
Если что-то трудно изобразить на чистом шелле, то на баше получится урод еще покруче. Как раз 3.5 случая, когда башизмы хорошо ложатся. Лично мне проще писать на примитивном и простом как палка шелле, чем зазубривать все особенности баша.
> чем зазубривать все особенности баша.которые к тому же могут быть не совместимыми между версиями
> Пытаться сделать что-то с POSIX-шеллом сложнее hello world — бесполезная трата времени.Так и запишем, - "не одолел" :)
На чистом шеле + стандартных утилитах типа sed, awk, tr, jq... можно написать большинство админовских задач ^значительно быстрее^ чем использование более высокоуровневых языков
> что за задачка такая странная? Зачем это вообще нужно?я хочу перепаковать. накопилось всякого в tar.gz, CPU и память есть.
в дальнейшем переведу упаковку логов в lzma.>> echo
> printfотказать. снижает читаемость.
> Зачем весь скрипт помещать внутрь гигантского ифа?
"структурное програмирование". слыхали про такую парадигму ?
> зачем универсальному кросс-дистровому скрипту
linux only. существенно используется
https://www.opennet.me/tips/3187_idle_cpulimit_limit_process...> почему ошибки идут в stdout, а не в stderr?
справделиво. я исправлю это.
> где стандартная преамбула, врубающая строгий режим?
в dash этого нет.
и наконец:
> > CopyLeft (L)
> Что за лицензия такая?как копирайт, только наоборот. google it.
> отказать. снижает читаемостьecho не надежен, т. к. не дает универсального интерфейса для вывода самых разных строк. Например, выведи мне строку "-n". Вот попробуй сам: echo -n
> "структурное програмирование". слыхали про такую парадигму ?
если весь код оформлять чисто структурно, то он быстро перейдет в трудноподдерживаемое состояние. Вместо этого следует использовать контрактное программирование, при котором все предусловия проверяются еще до начала работы. (Забудем на минуту, что конкретно в этом скрипте предусловия проверять вообще не надо -- пусть падает вызываемая прога.)
> linux only
че за рандомная ссылка? как она отвечает на мой вопрос?
> в dash этого нет.
Ну а в каких шеллах ты вообще проверял свой скрипт, раз хочешь "кросс-шелловость"? bash? csh? zsh? ash? fish?
> как копирайт, только наоборот. google it.
нет такой лицензии "копирайт". Нет такой лицензии "копилефт". google it: https://choosealicense.com/
Например, выведи мне строку "-n".
echo -e '\b-n'
> Например, выведи мне строку "-n".
> echo -e '\b-n'А если переносимо, чтоб и на bash и на dash?
Например, dash выдаст: -e-nВ стандарте на posix shell вообще нет echo.
printf '%s' "строка" # Вполне читаемо
>> Например, выведи мне строку "-n".
>> echo -e '\b-n'
> А если переносимо, чтоб и на bash и на dash?[ $SHELL == "dash" ] then
[ $SHELL == "bash" ] then
[ $SHELL == "mash" ] then
[ $SHELL == "sash" ] then> Например, dash выдаст: -e-n
On XSI-conformant systems, if the first operand is -n, it shall be treated as a string,
not an option. The following character sequences shall be recognized on XSI-conformant
systems within any of the arguments:Так что, это ты пишешь не по стандарту, а не echo плохое. :D
> В стандарте на posix shell вообще нет echo.
The Open Group Base Specifications Issue 7, 2018 edition
IEEE Std 1003.1-2017 (Revision of IEEE Std 1003.1-2008)
Copyright © 2001-2018 IEEE and The Open Grouphttps://pubs.opengroup.org/onlinepubs/9699919799.2018edition/
>>> Например, выведи мне строку "-n".
>>> echo -e '\b-n'
>> А если переносимо, чтоб и на bash и на dash?
> [ $SHELL == "dash" ] then
> [ $SHELL == "bash" ] then
> [ $SHELL == "mash" ] then
> [ $SHELL == "sash" ] thenКажется, вы предлагали echo для компактности. Все, гуляй компактность.
>> Например, dash выдаст: -e-n
> On XSI-conformant systems, if the first operand is -n, it shall be
> treated as a string,
> not an option. The following character sequences shall be recognized on XSI-conformant
> systems within any of the arguments:Прямо перед этим:
> If the first operand is -n, or if any of the operands contain a <backslash> character, the results are implementation-defined.===============
> Так что, это ты пишешь не по стандарту, а не echo плохое.
> :Dprintf един, а у echo
>APPLICATION USAGE
> It is not possible to use echo portably across all POSIX systems unless both -n (as the first argument) and escape sequences are omitted.
> The printf utility can be used portably to emulate any of the traditional behaviors of the echo utility as follows (assuming that IFS has its standard value or is unset):================
>> В стандарте на posix shell вообще нет echo.
> The Open Group Base Specifications Issue 7, 2018 edition
> IEEE Std 1003.1-2017 (Revision of IEEE Std 1003.1-2008)
> Copyright © 2001-2018 IEEE and The Open Group
> https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/Ну тогда уж сюда, а то еще раздел "Command language" искать.
https://pubs.opengroup.org/onlinepubs/9699919799.2018edition...И то - сам стандарт прямо говорит, что переносимость у echo так себе. Вот делать нечего, как зачитывать все эти имена вместо одной строчки printf. Не та цель.
echo - -n
> разных строк. Например, выведи мне строку "-n". Вот попробуй сам: echo -nЯ что то не понял, а в чем проблема?
echo -n '-n'
> хочу перепаковать .. в lzmazcat in.tar.gz | lzma > out.tar.xz
Использования неименованного канала командной оболочки предотвращает передачу метаданных сжатого файла tar-архива. Но метаданные файлов внутри tar-архива хранятся в самом tar-архиве и сохраняются, он вообще не распаковывается.
Так как и gzip, и xz (lzma) умеют сжимать только один файл, имеет смысл использовать их только в связке с tar, который обеспечит сохранность метаданных.
zcat in.tar.gz | lzma > out.tar.lzma
> zcat in.tar.gz | lzma > out.tar.lzmaне все так хорошо.
от использования cpulimit в tar.gz появился концевой мусор,
поэтому придеься усложнить проверку:
GZT=`mktemp`/usr/bin/eatmydata -- \
/usr/bin/nice -19 \
/usr/bin/chrt --idle 0 \
/usr/bin/ionice -c 3 \
gzip -vt $F.gz > $GZT 2>&1
RC=$?
if [ $RC -ge 1 ]; then
grep -q "decompression OK, trailing garbage ignored" $GZT
if [ $? -eq 0 ]; then
RC=0
else
echo error $RC in $F.gz : integrity test failed
rm $GZT
exit $RC
fi
fi
А зачем вот это все?> /usr/bin/eatmydata -- \
> /usr/bin/nice -19 \
> /usr/bin/chrt --idle 0 \
> /usr/bin/ionice -c 3 \
А скрипт просто ужасен. Переменные без кавычек после rm и mv - верный путь удалить себе ноги или переместить их вместо рук.Надо так:
mv -v -- "$F"
rm -v -- "$F"
Переменная проверяется до mv и rm, смысла нет засирать кавычками и флажками. Если что-то такое с пробелами в $F подсунуть, иф упадет.
У вас просто догма - нужно все обкавычивать, как бы чего не вышло.
Из каких конструкций можно понять, что переменная действительно проверяется до mv и rm? Неочевидно и неизвестно никому через два месяца.Без кавычек при вносе изменений придётся каждый раз, каждый раз, перечитывать всё, убеждаясь и разыскивая, что переменная проверяется до mv и rm. Это трата времени и внимания.
Подход с кавычками не требует анализировать весь скрипт каждый раз.
(Но, этот шелл такой шелл, что чтобы окавычивать и не перечитывать всё каждый раз с нуля, нужно окавычивать вообще всё всегда или сохраняется необходимость перечитки кода при вносе изменения. Такая магия развёртки переменных в кавычках и без, более-менее однозначность только если вообще всегда в кавычках. А иначе - тоже вчитываться надо опытному магу.)Потому кавычки упрощают в долгосрочной перспективе.
P.S. В Шелле нет хорошего способа программировать. Инструмент для другого. Инструмент админа для интеграции/связи утилит, написанных на богатых инструментами и средствами программирования языках.
> Переменная проверяется до mv и rm, смысла нет засирать кавычками и флажками.Дешёвые понты. "Засирать" - это как раз про такой говнокод, в котором нужно постоянно разбираться, что за чем проверялось. А двойные кавычки и EoO спасут ещё не один системный корень.
> У вас просто догма - нужно все обкавычивать, как бы чего не вышло.Значит вы еще не наступали на грабли, иначе бы знали почему шелчек ругается на безковычковые переменные
Но зачем в устаревший lzma, а не в xz?
> Но зачем в устаревший lzma, а не в xz?по результатам тестов. у lzma лучше результаты на этой коллекции.
zstd пробовали?
> zstd пробовали?Хорош, но очень уж голоден до памяти, S2 не хуже, быстрей и жрет памяти меньше
Мы всегда когда-то только учились.
"не нужно! этот ваш шелл нечитаемый. пишите на нормальных языках!"(я не знаю стандартные утилиты, не понимаю, зачем был сделан шелл, не знаю, что такое stdio и статус завершения процесса, пишу на питоне)
Выглядит как сарказм, зачем это минусовать.
Одно дело написать скриптец, чтобы он за вечерок перелопатил что-то, или за выходные, и совсем другое делать готовое решение, решение которое должно кроме защиты от инжектов включать защиты от двойного запуска, уметь определять когда оно было прервано, чтобы продолжать с нужного места, на баше это конечно делается, но настолько муторно, что проще переписать на чем-то вменяемом.
А чего тут муторного?PIDFILE="/run/myscript.pid"
if [ -f "${PIDFILE}" ]; then
pkill -0 -F "${PIDFILE}" \
&& echo "Script already run" \
&& exit 0 \
|| echo "Starting new instance"
fi
echo $$ > "${PIDFILE}"
> А чего тут муторного?
> PIDFILE="/run/myscript.pid"
> if [ -f "${PIDFILE}" ]; then
> pkill -0 -F "${PIDFILE}" \
> && echo "Script already run" \
> && exit 0 \
> || echo "Starting new instance"
> fi
> echo $$ > "${PIDFILE}"Если на полную катушку, то у шеллов (не только bash) должны быть стандартные пути для скриптов-библиотек, включая сами библиотеки. Вот это была бы моща.
Так это делают: source /папка/файлТолько тогда необходимость учитывать в каждый момент времени много скушных неочевидных обстоятельств. Которые в продвинутых языках не допускают для уменьшения числа ошибок.
Знания, что у каких-то топовых шелл 'set +e' будет принудительно сделан по POSIX при уровне вложенности более x (x=2, если верно помню), хоть бы и напишешь 'set -e'. И т.д. про '-o pipefail'. Что надёжные коды возврата из функций только строго беззнаковый байт.
Что если при 'set -x' есть $0 и $LINENO внутри PS4, то в случае source сработает неудобно.
Пространства имён переменных. Вот это всё про local, export... Проблемность глобальности переменных.
Кодить можно, но есть другие более предназначенные для того инструменты.
> Знания, что у каких-то топовых шелл 'set +e' будет принудительно сделан по POSIX при уровне вложенности более x (x=2, если верно помню), хоть бы и напишешь 'set -e'А это точно есть в posix?
posix-мануал для set про это ни слова (про опцию -e), да и слов force / nest там не найдено.По моему, если про это не сказано в стандарте, значит это против него).
'-o pipefail' тоже не по posix
# То же самое, но чуть более читаемоPIDFILE="/run/myscript.pid"
if [ -f "${PIDFILE}" ] && pkill -0 -F "${PIDFILE}"; then
echo "Script already run"
exit 0
fi
echo "Starting new instance"
echo $$ > "${PIDFILE}"
> А чего тут муторного?
> PIDFILE="/run/myscript.pid"
> if [ -f "${PIDFILE}" ]; then
> pkill -0 -F "${PIDFILE}" \
> && echo "Script already run" \
> && exit 0 \
> || echo "Starting new instance"
> fi
> echo $$ > "${PIDFILE}"Вроде бы есть утилитка, которая нечто подобное реализует.
LZMA было модно лет 15 назад, ща ZSTD в тренде. https://github.com/facebook/zstd
> LZMA было модно лет 15 назад, ща ZSTD в тренде. https://github.com/facebook/zstdS2 ИМХО значительно, лучше
> /usr/bin/nice -19 \
> /usr/bin/chrt --idle 0 \
> /usr/bin/ionice -c 3 \Дедовские методы и особо без гарантий.
# mount -t cgroup -o all cgroup /sys/fs/cgroup;
# mkdir /sys/fs/cgroup/$$
# cd /sys/fs/cgroup/$$
...
и понеслось рулить лимитами
...
Смузи выпил?
Так ведь у автора зато без sudo.
> Так ведь у автора зато без sudo.Афтор - чайник, у него "/usr/bin/nice -19",
он наверное не в курсе, что МИНУС 19 - это макс. приоритет в планировщике. :D
Не, ну мож наоборот, он гений. И вычислил, что комбинация: "nice -19, chrt --idle 0, ionice -c 3"
даёт минимальный оверхэд. Типа в планировщике по-быстренькому отдуплился и дальше ждать ушёл.
Но у меня такое ощщущенние, что это больше на DoS похоже.
В планировщике задач будет часто появляться, при этом у таймера будет приоритет IDLE 0,
но планировщик его не вытолкнет, будет ждать окончания ionice 3;
> Афтор - чайник, у него "/usr/bin/nice -19",
> он наверное не в курсе, что МИНУС 19 - это макс. приоритет
> в планировщике. :Dтонко !
я даже начал сомневаться в себе. но потом проверил.0) есть builtin nice в разных шеллах, несовместимое внутри себя. а есть вот чего:
$ file /usr/bin/nice
/usr/bin/nice: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=2d64570259ee4ea90022ff7c87afbce7b6366f17, for GNU/Linux 3.2.0, stripped
я по очевидным причинам использую именно это.
1) man top
/NI
13. NI -- Nice Value
The nice value of the task. A negative nice value means higher priority, whereas a
positive nice value means lower priority. Zero in this field simply means priority will
not be adjusted in determining a task's dispatch-ability.2) и вот представьте себе, процессы запущенные через "/usr/bin/nice -19"
по данным top имеют NI = 19 (плюс 19),
а треды ядра типа rcu* и mm* имеют NI = -20 (минус двадцать).что бы это значило ?
Косяк это шелов и окружений (env), если nice -19 exec у тебя показывает наименьший,
то nice 19 exec не сможешь указать. Чтоб работало везде пиши: nice -n 19 или nice -n -19;> а треды ядра типа rcu* и mm* имеют NI = -20 (минус двадцать).
> что бы это значило ?Это значит у них максимальный приоритет!!!
> Чтоб работало везде пиши: nice -n 19 или nice -n -19;отказать. чтобы работало везде надо вызывать /usr/bin/nice именно так как написано.
> Но у меня такое ощщущенние, что это больше на DoS похоже.Угу, у меня такое-же мнение
Скрипт прочтения man gz lzma bash
#!/bin/bash
#
# перед стартом проверить наличие find, file, rename, stat, chmod, chown, touch, zcat, lzma, ...for d in $(find -noleaf -xdev -type d)
do
pushd .;
cd $d
for i in $(ls -1 *[gG][zZ]); # .tgz, .GZ тоже бывают.
do
if [ "$(file --mime-type $i|cut -d' ' -f2)" != "application/gzip" ];
then
continue;
fi
# тут должно быть определение прав доступа на (запись, chmod/chown оригинала)
zcat $i | lzma -cz9 > $i.lzma;
touch -a -d "`stat -c '%x' $i`" $i.lzma;
touch -m -d "`stat -c '%y' $i`" $i.lzma;
chown "`stat --printf '%u:%g' $i`" $i.lzma;
chmod "`stat -c '%a' $i`" $i.lzma;
rename 's/gz.lzma/lzma/' $i.lzma
rm $i;
done;
popd;
done
> if [ "$(file --mime-type $i|cut -d' ' -f2)" != "application/gzip" ]; then continue; ficase "$(env LC_ALL=C file --mime-type --brief -- "${i}")" in application/gzip) continue ;; esac
[~/src]:$ file --ver
file-5.33
magic file from /etc/magic:/usr/share/misc/magic[~/src]:$ file --mime-type gpu_burn-0.4.tar.gz
gpu_burn-0.4.tar.gz: application/x-gzip--
надо бы ещё проверять, а все ли утилиты файл возвращают application/gzip или кто-то application/x-gzip?
> надо бы ещё проверять, а все лиЯ тож считают, что за время гемора в разработке этого скрипта,
можно было заработать на покупку 100Tb SSD. Это к вопросу об экономии места.Портабельность тут почти на нуле. Напр. на SCO UNIX иль IRIX 7 не взлетит.
Не полетит на busybox-based дистрах, в Андроидах, скорее всего с BSD до 9 будут проблемы...
Для универсальности надо либо писать на ANSI C89/C++98/Perl 2.0/Python2,
либо тестить скрипты в csh на FreeBSD/NetBSD версий 1997-2000 годов.
> for i in $(ls -1 *[gG][zZ]);С этим можно хорошенько нарваться если в директории будет очень много файлов, т.к. можно легко нарваться на лимит CLI