#!/bin/sh # defrag v0.07 by Con Kolivas /dev/null abort() { echo -e "\nВыполнение прервано успешно" rm -f tmpfile dirlist exit 1 } fail() { echo -e "\nFailed! Проверьте целостность последнего файла" abort } declare -i filesize=0 declare -i numfiles=0 declare -i in_chunks=0 declare -i out_chunks=0 #The maximum size of a file we can easily cache in ram declare -i maxsize=$((`awk '/MemTotal/ {print $2}' /proc/meminfo`*1024)) (( maxsize-= `awk '/Mapped/ {print $2}' /proc/meminfo` )) (( maxsize/= 2)) if [[ -a tmpfile || -a dirlist ]] ; then echo dirlist or tmpfile exists exit 1 fi # Sort in the following order: # 1) Depth of directory # 2) Size of directory descending # 3) Filesize descending # I made this crap up. I'ts completely unvalidated. echo -e "Создаю список файлов для обработки... \c" #stupid script to find max directory depth find -xdev -type d -printf "%d\n" | sort -n | uniq > dirlist #sort directories in descending size order cat dirlist | while read d; do find -xdev -type d -mindepth $d -maxdepth $d -printf "\"%p\"\n" | \ xargs du -bS --max-depth=0 | \ sort -k 1,1nr -k 2 |\ cut -f2 >> tmpfile if (( $? )) ; then fail fi done rm -f dirlist #sort files in descending size order cat tmpfile | while read d; do find "$d" -xdev -type f -maxdepth 1 -printf "%s\t%p\n" | \ sort -k 1,1nr | \ cut -f2 >> dirlist if (( $? )) ; then fail fi done rm -f tmpfile numfiles=`wc -l dirlist | awk '{print $1}'` echo -e "готово, $numfiles файла(-ов) будут дефрагментированы" #copy to temp file, check the file hasn't changed and then overwrite original cat dirlist | while read i; do (( --numfiles )) if [[ ! -f $i ]]; then continue fi #We could be this paranoid but it would slow it down 1000 times #if [[ `lsof -f -- "$i"` ]]; then # echo -e "\n File $i open! Skipping" # continue #fi filesize=`find "$i" -printf "%s"` # read the file first to cache it in ram if possible if (( filesize < maxsize )) then echo -e "\rещё $numfiles, (кэширую в озу)...\c" cat "$i" > /dev/null else echo -e "\rещё $numfiles, двигаю $filesize байт...\c" fi in_chunks=`filefrag "$i" | awk '{print $(NF - 2)}'` datestamp=`find "$i" -printf "%s"` if (( in_chunks != 1 )) then cp -a -f "$i" tmpfile out_chunks=`filefrag "tmpfile" | awk '{print $(NF - 2)}'` if (( out_chunks < in_chunks )) then # check the file hasn't been altered since we copied it if [[ `find "$i" -printf "%s"` != $datestamp ]] ; then echo -e " \e[1;41mисходный файл изменился, пропускаю\e[0m" continue fi echo -e " \e[1;36m($in_chunks-->$out_chunks) дефрагментирован $i\e[0m" mv -f tmpfile "$i" else echo -e " \e[3;36m $out_chunks не лучше $in_chunks, пропускаю $i\e[0m" rm tmpfile fi else echo -e " \e[1;34mфайл $i не фрагментирован, пропускаю\e[0m" continue fi if (( $? )) ; then fail fi done echo -e "\nЗавершено успешно" rm -f dirlist