Вопрос или проблема
Я пытаюсь удалить строки из нескольких таблиц в нескольких базах данных. Прикрепленный скрипт показывает только одну базу данных, но массив содержит список из четырех баз данных.
#!/bin/bash
declare -a DB_ARRAY=("delete_test")
where_clause="where crt_tm between date_format('2022-04-01 00:00:00','%Y-%m-%d 00:00:00') and date_format('2023-03-31 23:59:59','%Y-%m-%d 23:59:59')"
log='/data/scripts_logs/delete.log'
#Следующие пути входа используются в операторе CASE ниже.
#[path1]
path1='pt_archiver'
delete_from_wallet_order_deposit(){
for DB in "${DB_ARRAY[@]}"
do
for file in `find /data/bkp/${DB}/ -type f -name "*.sql" | awk -F "https://unix.stackexchange.com/" '{ print $5 }'`
do
table_name=`echo ${file} | awk -F '.' '{ print $1 }'`
#echo ${DB}.${table_name}
case ${DB} in
delete_test)
count=`mysql --login-path=${path1} --silent --skip-column-names ${DB} -e "select count(*) from ${table_name} ${where_clause};"`
echo ${count}
if [ ${count} != 0 ]
then
echo "Общее количество строк в ${DB}.${table_name} составляет ${count}." >> ${log}
echo "Эти строки будут удалены." >> ${log}
while [ ${count} -gt 0 ]
do
mysql --login-path=${path1} --init-command="SET SQL_LOG_BIN = 0" ${DB} -e "delete from ${table_name} ${where_clause} order by crt_tm limit 5000; select sleep(5);" &>> ${log}
done
if [ $? -eq 0 ]
then
echo "Успешно удалено ${count} строк из ${DB}.${table_name}." >> ${log}
else
echo "Проверьте журнал ошибок."
fi
fi
;;
esac
done
done
}
В каждой таблице нужно удалить около 40000 строк, и таких таблиц несколько.
Я понимаю, что, когда count > 0, он заходит в цикл IF, а затем, пока count больше 0, он должен войти в цикл WHILE и начать удалять 5000 строк, и должен выйти, когда строки удалены, но он застревает в бесконечном цикле. Я явно что-то упускаю. Пожалуйста, помогите мне понять, что именно я упускаю. Также может быть более эффективный способ сделать это, но это не то, что я ищу. Я просто пытаюсь понять, как работает цикл WHILE. Я использовал цикл for, и я понимаю его, но явно не цикл WHILE.
Должен ли я добавить еще один select после delete (в WHILE) и снова захватить count? Это то, что я упускаю?
Ответ или решение
Для того чтобы понять, как работает цикл WHILE в Bash, важно обратиться к структуре вашего скрипта, который вы предоставили, а также к основным принципам работы циклов в Bash.
Что такое цикл WHILE?
Цикл WHILE в Bash выполняет набор команд до тех пор, пока заданное условие истинно. Его общая форма выглядит следующим образом:
while условие; do
команды
done
В вашем скрипте вы используете цикл WHILE для удаления строк из таблиц в базе данных. Но почему он зацикливается? Давайте это выясним.
Разбор вашего кода
Ваш цикл WHILE такой:
while [ ${count} -gt 0 ]
do
mysql --login-path=${path1} --init-command="SET SQL_LOG_BIN = 0" ${DB} -e "delete from ${table_name} ${where_clause} order by crt_tm limit 5000; select sleep(5);" >> ${log}
done
Здесь переменная count
проверяется на то, больше ли она нуля. Однако, вы нигде не обновляете значение переменной count
внутри цикла. Это и приводит к бесконечному циклу. count
остается прежним, и цикл продолжает выполняться бесконечно, так как условие [ ${count} -gt 0 ]
всегда истинно, если только вы не измените значение count
.
Как исправить ситуацию
Чтобы исправить ваш код, вам действительно нужно обновить count
в каждом цикле WHILE. Для этого можно добавить еще один запрос, чтобы получить текущее количество строк, которые необходимо удалить, перед тем как завершить одну итерацию цикла:
while [ ${count} -gt 0 ]
do
mysql --login-path=${path1} --init-command="SET SQL_LOG_BIN = 0" ${DB} -e "delete from ${table_name} ${where_clause} order by crt_tm limit 5000; select sleep(5);" >> ${log}
# Обновляем значение count
count=`mysql --login-path=${path1} --silent --skip-column-names ${DB} -e "select count(*) from ${table_name} ${where_clause};"`
done
Таким образом, после каждого удаления вы будете обновлять count
, и цикл завершится, когда количество оставшихся строк станет равным нулю.
Заключение
Цикл WHILE — это мощный инструмент в Bash, который может помочь при выполнении повторяющихся задач до тех пор, пока не будет достигнуто определенное условие. Важно всегда следить за изменением переменных, используемых в условиях циклов, чтобы избежать бесконечных циклов, как в вашем случае.
Также, хотя в вашем случае вы ищете понимания цикла WHILE, стоит отметить, что для улучшения производительности вашего скрипта можно рассмотреть другие конструкции или даже другие языки программирования, если задачи становятся слишком громоздкими.
Если у вас возникнут дополнительные вопросы или нужна дальнейшая помощь, не стесняйтесь обращаться!