Я должен создать резервный сценарий (удар) базы данных MySQL. Когда я выполню сценарий, sql файл будет создан в "/home/user/Backup". Проблема, я также должен сделать сценарий, который удаляет самый старый файл, если существует больше чем 7 файлов в ".../резервное копирование". Кто-то знает, как сделать это? Я попробовал все, но этому не удалось каждый раз считать файлы в каталоге и обнаружить самый старый...
Позволяет, рассматривают проблему: задача состоит в том, чтобы проверить, ли количество файлов в особенности каталог по определенному числу, и удалите самый старый файл среди тех. Сначала может казаться, что мы должны пересечь дерево каталогов однажды подсчет файлов, затем пересечь его снова, чтобы найти время последнего изменения всех файлов, отсортировать их и извлечь самое старое для удаления. Но полагая, что в данном случае OP упомянула, что удалила файлы, если и только если количество файлов выше 7, оно предполагает, что мы можем просто получить список всех файлов с их метками времени однажды и сохранить их в переменную.
проблемой с этим подходом является опасность, связанная с именами файлов. Как был упомянут в комментариях, никогда не рекомендуется проанализировать ls
команда, так как вывод может содержать специальные символы и повредить сценарий. Но, как некоторые из Вас могут знать в подобных Unix системах (и Ubuntu также), каждый файл имеет inode число, связанное с нею. Таким образом создание списка записей с метками времени (в секундах для легкой числовой сортировки) плюс inode число, разделенное новой строкой, гарантирует, что мы безопасно анализируем имена файлов. Удаление самого старого имени файла может также быть сделано тот путь.
сценарий, представленный ниже, делает точно, как описано выше.
, Важный : прочитайте комментарии, особенно в delete_oldest
функция.
#!/bin/bash
# Uncomment line below for debugging
#set -xv
delete_oldest(){
# reads a line from stdin, extracts file inode number
# and deletes file to which inode belongs
# !!! VERY IMPORTANT !!!
# The actual command to delete file is commented out.
# Once you verify correct execution, feel free to remove
# leading # to uncomment it
read timestamp file_inode
find "$directory" -type f -inum "$file_inode" -printf "Deleted %f\n"
# find "$directory" -type f -inum "$file_inode" -printf "Deleted %f\n" -delete
}
get_files(){
# Wrapper function around get files. Ensures we're working
# with files and only on one specific level of directory tree
find "$directory" -maxdepth 1 -type f -printf "%Ts\t%i\n"
}
filecount_above_limit(){
# This function counts number of files obtained
# by get_files function. Returns true if file
# count is greater than what user specified as max
# value
num_files=$(wc -l <<< "$file_inodes" )
if [ $num_files -gt "$max_files" ];
then
return 0
else
return 1
fi
}
exit_error(){
# Print error string and quit
printf ">>> Error: %s\n" "$1" > /dev/stderr
exit 1
}
main(){
# Entry point of the program.
local directory=$2
local max_files=$1
# If directory is not given
if [ "x$directory" == "x" ]; then
directory="."
fi
# check arguments for errors
[ $# -lt 1 ] && exit_error "Must at least have max number of files"
printf "%d" $max_files &>/dev/null || exit_error "Argument 1 not numeric"
readlink -e "$directory" || exit_error "Argument 2, path doesn't exist"
# This is where actual work is being done
# We traverse directory once, store files into variable.
# If number of lines (representing file count) in that variable
# is above max value, we sort numerically the inodes and pass them
# to delete_oldest, which removes topmost entry from the sorted list
# of lines.
local file_inodes=$(get_files)
if filecount_above_limit
then
printf "@@@ File count in %s is above %d." "$directory" $max_files
printf "Will delete oldest\n"
sort -k1 -n <<< "$file_inodes" | delete_oldest
else
printf "@@@ File count in %s is below %d." "$directory" $max_files
printf "Exiting normally"
fi
}
main "$@"
$ ./delete_oldest.sh 7 ~/bin/testdir
/home/xieerqi/bin/testdir
@@@ File count in /home/xieerqi/bin/testdir is below 7.Exiting normally
$ ./delete_oldest.sh 7 ~/bin
/home/xieerqi/bin
@@@ File count in /home/xieerqi/bin is above 7.Will delete oldest
Deleted typescript
Это, вероятно, страшно.. длинный .and.. .and похож на него, делает слишком много. И это могло бы быть. На самом деле все можно пихнуть на одну строку командной строки (очень измененная версия предложения muru, отправленного в чат , который имеет дело с именами файлов. echo
используется вместо rm
в демонстрационных целях):
find /home/xieerqi/bin/testdir/ -maxdepth 1 -type f -printf "%T@ %p\0" | sort -nz | { f=$(awk 'BEGIN{RS=" "}NR==2{print;next}' ); echo "$f" ; }
Однако у меня есть несколько вещей, мне не нравится приблизительно это:
awk
команда, которая, вероятно, порвет с именами файлов, которые имеют пробелы) Так, в то время как мой сценарий выглядит ужасно гигантским для простой задачи, это делает всех больше проверок и имеет целью решать проблему со сложными именами файлов. Это, вероятно, было бы короче и более идиоматичным для реализации в Perl или Python (который я абсолютно могу сделать, я просто, оказалось, выбрал bash
для этого вопроса).
Я думаю, что ответ @Serg хорош, и я учусь от него и от @muru. Я сделал этот ответ, потому что я хотел исследовать и изучить, как создать файл сценария оболочки на основе вывода от find
с 'действием' -print
для сортировки файлов согласно времени, они были созданы/изменены. Предложите улучшения и bugfixes (при необходимости).
Как Вы заметите, стиль программирования очень отличается. Мы можем сделать вещи во многих отношениях в Linux :-)
Я сделал сценарий оболочки удара для соответствия требованиям OP, @beginner27 _, но не слишком трудно изменить его в других но подобных целях.
Следующий снимок экрана показывает, как он был протестирован: Одиннадцать файлов были созданы, и сценарий (который находится в ~ / мусорное ведро и имеет, выполняются, полномочия) выполняется. Я удалил # символ из строки
# bash "$cmd"
сделать его
bash "$cmd"
В первый раз сценарий обнаруживает и печатает эти одиннадцать файлов, семь новейших файлов с синим фоном и четыре самых старых файла с красным фоном. Четыре самых старых файла удалены. Скрипт запущен во второй раз (только для демонстрации). Это обнаруживает и печатает оставление семью файлами и удовлетворено, 'Нет никакого файла резервной копии для удаления'.
Решающее find
команда, которая сортирует файлы согласно времени, похожа на это,
find "$bupdir" -type f -printf "%T+ %p\0"|sort -nrz > "$srtlst"
Вот файл сценария. Я сохранил его в ~/bin
с именем rm_old_backups
, но можно дать ему любое имя, пока это уже не вмешивается в некоторых существующее название исполняемой программы.
#!/bin/bash
keep=7 # set the number of files to keep
# variables and temporary files
inversvid="\0033[7m"
resetvid="\0033[0m"
redback="\0033[1;37;41m"
greenback="\0033[1;37;42m"
blueback="\0033[1;37;44m"
bupdir="$HOME/Backup"
cmd=$(mktemp)
srtlst=$(mktemp)
rmlist=$(mktemp)
# output to the screen
echo -e "$inversvid$0:
keep $keep backup files, remove the oldest files, if more than $keep are found $resetvid"
echo "Security fix: You must edit this script and remove the # character from
a line near the end of the script '# bash \"\$cmd\"' --> 'bash \"\$cmd\"'
otherwise the script will only show what it can do. Please test that it
works correctly before you remove that # character!"
# the crucial find command, that sorts the files according to time
find "$bupdir" -type f -printf "%T+ %p\0"|sort -nrz > "$srtlst"
# more output
echo -e "${inversvid}time-stamp file-name $resetvid"
echo -en "$blueback"
sed -nz -e 1,"$keep"p "$srtlst" | tr '\0' '\n'
echo -en "$resetvid"
echo -en "$redback"
sed -z -e 1,"$keep"d "$srtlst" | tr '\0' '\n' | tee "$rmlist"
echo -en "$resetvid"
# remove oldest files if more files than specified are found
if test -s "$rmlist"
then
echo rm '"'$(sed -z -e 1,"$keep"d -e 's/[^ ]* //' -e 's/$/" "/' "$srtlst")'"'\
| sed 's/" ""/"/' > "$cmd"
cat "$cmd"
# uncomment the following line to really remove files
# bash "$cmd"
echo "The oldest backup files are removed"
else
echo "There is no old backup file to remove"
fi
# remove temporary files
rm $cmd $srtlst $rmlist