Возникла задача сконвертировать очень много файлов из одного формата в другой. Данный скрипт делает это с распараллеливанием, что ускоряет процесс. Плюс, есть прогресс выполнения и логгирования. Можно с лёгкостью адаптировать под что угодно, где требуется параллельное выполнение типовых задач по списку файлов =)
# Многопоточная перекодировка файлов asterisk
# Для работы в Ubuntu требует наличия vorbis-tools
# количество потоков обработки
THREADS=8
# рабочая папка где будут искаться исходные файлы
SCAN_DIR='/var/spool/asterisk/monitor'
WORK_DIR="$(dirname $(readlink -f $0))"
SCAN_FILE="$WORK_DIR/files_to_convert"
LOG_FILE="$WORK_DIR/convert.log"
LOGTMP_FILE="$WORK_DIR/convert.tmp"
RATIO_FILE="$WORK_DIR/ratio.tmp"
renice="ionice -c3 nice -n20"
# если нет файла со списком файлов для конвертации - создадим
if [ ! -f "$SCAN_FILE" ]; then
printf '[%s] Collecting files to convert...' "`date`" >> "$LOG_FILE"
# ищем файлы, с расширением .wav и последним изменением более суток назад
eval "$renice find \"$SCAN_DIR\" -type f -mtime +0 -daystart -iname '*.wav' > \"$SCAN_FILE\""
else
printf '[%s] Previous scan result used...' "`date`" >> "$LOG_FILE"
fi
# общее количество файлов для обработки = числу строк в файле скана
files_total=$(cat "$SCAN_FILE" | wc -l)
printf ' %s found total\n' "$files_total" >> "$LOG_FILE"
# основная функция конвертации, вызывается дочерними процессами
process_file(){
local num="${1% $'\t'*}"
local record="${1##*$'\t' }"
# если исходный файл ненулевой
if [ -s "$record" ]; then
local newfile="${record%.*}.ogg"
eval "$renice /usr/bin/oggenc -Q -q1 \"$record\" -o \"$newfile\""
# если конвертация прошла без ошибок, то выставим права, время создания исходного файла и удалим старый
if [ $? -eq 0 ]; then
# запишем статистику по исходному и получившемуся файлам
printf '%s\t%s\n' "$(stat --printf="%s" "$record")" "$(stat --printf="%s" "$
newfile")" >> "$RATIO_FILE"
chown --reference="$record" "$newfile"
chmod --reference="$record" "$newfile"
touch -r "$record" "$newfile"
rm -f "$record"
printf '[%s] (%s of %s) %s converted\n' "`date`" "$num" "$files_total" "$rec
ord">> "$LOGTMP_FILE"
fi
# исходный файл нулевой - удалим его
else
rm -f "$record"
printf '[%s] (%s of %s) %s is null file, removed\n' "`date`" "$num" "$files_tota
l" "$record">> "$LOGTMP_FILE"
fi
}
# даём доступ новым процессам к некоторым переменным из этого скрипта
export -f process_file
export files_total
export LOGTMP_FILE
export RATIO_FILE
# если есть что конвертировать, запускаем ацкий конверт
if [ -s "$SCAN_FILE" ]; then
awk '{print NR, "\t", $0}' "$SCAN_FILE" | xargs -d'\n' -L1 -n1 -P $THREADS /bin/bash
-c 'process_file "$@"' _
# по итогу, посчитаем суммарный исходный и сконвертированный размер файлов
awk '
function hum(input,v,s) {
split("KB MB GB TB", v, " ")
if(input + 0.0 == input){
while( input > 1024 ){
input /= 1024 ; s++
}
return sprintf("%0.2f %s", input, v[s])
} else {return input}
}
BEGIN {FS="\t";OFS=""}
{orig+=$1;conv+=$2}
END {
print ("[",
strftime(),
"] Files converted, source/result summary: ",
hum(orig),
" / ",
hum(conv));
}' "$RATIO_FILE" >> "$LOG_FILE"
fi
rm -f "$SCAN_FILE"
rm -f "$LOGTMP_FILE"
rm -f "$RATIO_FILE"
Версия 2 с ренайсами =)
#!/bin/bash
# Многопоточная перекодировка файлов asterisk
# Для работы в Ubuntu требует наличия vorbis-tools
# количество потоков обработки
THREADS=8
# рабочая папка где будут искаться исходные файлы
SCAN_DIR='/var/spool/asterisk/monitor'
WORK_DIR="$(dirname $(readlink -f $0))"
SCAN_FILE="$WORK_DIR/files_to_convert"
LOG_FILE="$WORK_DIR/convert.log"
LOGTMP_FILE="$WORK_DIR/convert.tmp"
RATIO_FILE="$WORK_DIR/ratio.tmp"
renice="ionice -c3 nice -n20"
# если нет файла со списком файлов для конвертации - создадим
if [ ! -f "$SCAN_FILE" ]; then
printf '[%s] Collecting files to convert...' "`date`" >> "$LOG_FILE"
# ищем файлы, с расширением .wav и последним изменением более суток назад
eval "$renice find \"$SCAN_DIR\" -type f -mtime +0 -daystart -iname '*.wav' > \"$SCAN_FILE\""
else
printf '[%s] Previous scan result used...' "`date`" >> "$LOG_FILE"
fi
# общее количество файлов для обработки = числу строк в файле скана
files_total=$(cat "$SCAN_FILE" | wc -l)
printf ' %s found total\n' "$files_total" >> "$LOG_FILE"
# основная функция конвертации, вызывается дочерними процессами
process_file(){
local num="${1% $'\t'*}"
local record="${1##*$'\t' }"
# если исходный файл ненулевой
if [ -s "$record" ]; then
local newfile="${record%.*}.ogg"
eval "$renice /usr/bin/oggenc -Q -q1 \"$record\" -o \"$newfile\""
# если конвертация прошла без ошибок, то выставим права, время создания исходного файла и удалим старый
if [ $? -eq 0 ]; then
# запишем статистику по исходному и получившемуся файлам
printf '%s\t%s\n' "$(stat --printf="%s" "$record")" "$(stat --printf="%s" "$
newfile")" >> "$RATIO_FILE"
chown --reference="$record" "$newfile"
chmod --reference="$record" "$newfile"
touch -r "$record" "$newfile"
rm -f "$record"
printf '[%s] (%s of %s) %s converted\n' "`date`" "$num" "$files_total" "$rec
ord">> "$LOGTMP_FILE"
fi
# исходный файл нулевой - удалим его
else
rm -f "$record"
printf '[%s] (%s of %s) %s is null file, removed\n' "`date`" "$num" "$files_tota
l" "$record">> "$LOGTMP_FILE"
fi
}
# даём доступ новым процессам к некоторым переменным из этого скрипта
export -f process_file
export files_total
export LOGTMP_FILE
export RATIO_FILE
# если есть что конвертировать, запускаем ацкий конверт
if [ -s "$SCAN_FILE" ]; then
awk '{print NR, "\t", $0}' "$SCAN_FILE" | xargs -d'\n' -L1 -n1 -P $THREADS /bin/bash
-c 'process_file "$@"' _
# по итогу, посчитаем суммарный исходный и сконвертированный размер файлов
awk '
function hum(input,v,s) {
split("KB MB GB TB", v, " ")
if(input + 0.0 == input){
while( input > 1024 ){
input /= 1024 ; s++
}
return sprintf("%0.2f %s", input, v[s])
} else {return input}
}
BEGIN {FS="\t";OFS=""}
{orig+=$1;conv+=$2}
END {
print ("[",
strftime(),
"] Files converted, source/result summary: ",
hum(orig),
" / ",
hum(conv));
}' "$RATIO_FILE" >> "$LOG_FILE"
fi
rm -f "$SCAN_FILE"
rm -f "$LOGTMP_FILE"
rm -f "$RATIO_FILE"
Версия 2 с ренайсами =)
Комментариев нет:
Отправить комментарий