Бид энэ ажлаар ямар нэгэн скрипт бичихгүй, харин бичсэн скриптийг нарийн судалж скрипт бичих аргуудыг сурах болно. Гол маш сайн судалж ойлгох хэрэгтэй. Скрипт ~/sw302/lab05/ufa.sh нэртэйгээр үүсэх ёстой. Шалгах хугацаа:VI
Дараах бодолтыг ажиллуулж туршиж үз. Хамгийн гол нь ойлгож өөрийн болгох хэрэгтэй.
#!/bin/bash
#----functions start------------------------------------------------------------
function usage() {
}
function filter_older_than() {
}
function filter_newer_than() {
}
function filter_date_between() {
}
function filter_bigger_than() {
}
function filter_smaller_than() {
}
function filter_words() {
}
function filter_namefilter() {
}
function filter_keep_total_size_under() {
}
function action_list() {
}
function action_list_detail() {
}
function action_delete() {
}
function action_replace() {
}
function action_newrepository {
}
#----functions end--------------------------------------------------------------
# sanity check
if [ $# = 0 ] ; then usage; fi
# exit status
ec_bad_command=-1
ec_no_match=-2
ec_unexpected_param=-3
ec_failed_command=-4
ec_bad_param=-5
# setup :- defaults
repository=~/sw302/lab05/repository
date_format=%Y%m%d%H%M.%S
date_file_1=.junk1
date_file_2=.junk2
# setup :- variables for filter
filter=$1
filter_param_1=''
filter_param_2=''
filter_param_count=0
filter_matched=''
# setup :- variables for action
action=''
action_param_1=''
# main filter dispatcher
case '${filter}' in
'--help')
usage
;;
'--older_than')
;;
'--newer_than')
;;
'--date_between')
;;
'--bigger_than')
;;
'--smaller_than')
;;
'--words')
;;
'--namefilter')
;;
'--keep_total_size_under')
;;
*)
usage
;;
esac
#----functions start------------------------------------------------------------
function usage() {
}
function filter_older_than() {
}
function filter_newer_than() {
}
function filter_date_between() {
}
function filter_bigger_than() {
}
function filter_smaller_than() {
}
function filter_words() {
}
function filter_namefilter() {
}
function filter_keep_total_size_under() {
}
function action_list() {
}
function action_list_detail() {
}
function action_delete() {
}
function action_replace() {
}
function action_newrepository {
}
#----functions end--------------------------------------------------------------
# sanity check
if [ $# = 0 ] ; then usage; fi
# exit status
ec_bad_command=-1
ec_no_match=-2
ec_unexpected_param=-3
ec_failed_command=-4
ec_bad_param=-5
# setup :- defaults
repository=~/sw302/lab05/repository
date_format=%Y%m%d%H%M.%S
date_file_1=.junk1
date_file_2=.junk2
# setup :- variables for filter
filter=$1
filter_param_1=''
filter_param_2=''
filter_param_count=0
filter_matched=''
# setup :- variables for action
action=''
action_param_1=''
# main filter dispatcher
case '${filter}' in
'--help')
usage
;;
'--older_than')
;;
'--newer_than')
;;
'--date_between')
;;
'--bigger_than')
;;
'--smaller_than')
;;
'--words')
;;
'--namefilter')
;;
'--keep_total_size_under')
;;
*)
usage
;;
esac
Энэ бол манай скриптийн ерөнхий бүтэц. Бид дараа нь илүү нарийвчилж гүйцээх болно. Ерөнхий санаа нь:
- case -г олон функцүүдийн 'диспетчер' маягаар ашиглах -- Лаб #4 -т байсантай ижилхэн.
- Шүүлтүүр 'filter' бүрт, мөн үйлдэл 'action' бүрт зориулж функц үүсгэх.
- Скриптэд болон зарим функцүүдэд ашиглагдах хувьсагчдыг үүсгэх.
Алхам #2 - Эхлээд амарханыг нь хий
- source: ~/sw302/lab05/ufa.sh
function usage() {
echo -e '\
`basename $0`: Invalid command!
GET HELP:
ufa.sh [ --help ]
FILTER & ACTION:
ufa.sh [ [ --older_than | --newer_than ] date | --date_between date1 date2 ] --|
[ ( --bigger_than | --smaller_than ) file_size_in_byte ] |--> FILTER
[ --words words ... | --namefilter filenames_filters ... ] --|
[ --delete ] --|
[ --list ] |
[ --list_detail ] |--> ACTION
[ --replace replace_word ] |
[ --newrepository repository_name_tar.gz ] --|
TRIM:
ufa.sh [ --keep_total_size_under total_repository_size_in_bytes ] |--> TRIM REPOSITORY'
exit $ec_bad_command
}
echo -e '\
`basename $0`: Invalid command!
GET HELP:
ufa.sh [ --help ]
FILTER & ACTION:
ufa.sh [ [ --older_than | --newer_than ] date | --date_between date1 date2 ] --|
[ ( --bigger_than | --smaller_than ) file_size_in_byte ] |--> FILTER
[ --words words ... | --namefilter filenames_filters ... ] --|
[ --delete ] --|
[ --list ] |
[ --list_detail ] |--> ACTION
[ --replace replace_word ] |
[ --newrepository repository_name_tar.gz ] --|
TRIM:
ufa.sh [ --keep_total_size_under total_repository_size_in_bytes ] |--> TRIM REPOSITORY'
exit $ec_bad_command
}
Алхам #3 - Шүүлтүүрүүд
- source: ~/sw302/lab05/ufa.sh
function filter_older_than() {
assert_not_null $filter_param_1 $filter
touch -t $filter_param_1 $date_file_1
filter_matched=`find $repository \! -newer $date_file_1 -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_newer_than() {
assert_not_null $filter_param_1 $filter
touch -t $filter_param_1 $date_file_1
filter_matched=`find $repository -newer $date_file_1 -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_date_between() {
assert_not_null $filter_param_1 $filter
assert_not_null $filter_param_2 $filter
touch -t $filter_param_1 $date_file_1
touch -t $filter_param_2 $date_file_2
filter_matched=`find $repository -newer $date_file_1 \! -newer $date_file_2 -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_bigger_than() {
assert_not_null $filter_param_1 $filter
filter_matched=`find $repository -size +${filter_param_1}c -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_smaller_than() {
assert_not_null $filter_param_1 $filter
filter_matched=`find $repository -size -${filter_param_1}c -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_words() {
assert_not_null $filter_param_1 $filter
filter_matched=`grep -rlEw $filter_param_1 $repository`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_namefilter() {
assert_not_null $filter_param_1 $filter
filter_matched=`find $repository -regextype posix-extended -regex '^.*/[^\/]*(${filter_param_1})[^\/]*$' -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_keep_total_size_under() {
assert_not_null $filter_param_1 $filter
local allfiles=`find $repository -size +1c -type f -printf %h/%f:%s\\\n | sort -rn -t \: -k 2`
local currentsize=0
local maxsize=$(($filter_param_1-1))
local delete_all='false'
for a in $allfiles ; do
if [ '${delete_all}' == 'true' ] ; then
rm -f `echo $a | cut -d \: -f 1` &> /dev/null
continue
fi
currentsize=$(($currentsize+`echo $a | cut -d \: -f 2`))
if [ $currentsize -gt $maxsize ] ; then
rm -f `echo $a | cut -d \: -f 1` &> /dev/null
delete_all='true'
fi
done
}
assert_not_null $filter_param_1 $filter
touch -t $filter_param_1 $date_file_1
filter_matched=`find $repository \! -newer $date_file_1 -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_newer_than() {
assert_not_null $filter_param_1 $filter
touch -t $filter_param_1 $date_file_1
filter_matched=`find $repository -newer $date_file_1 -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_date_between() {
assert_not_null $filter_param_1 $filter
assert_not_null $filter_param_2 $filter
touch -t $filter_param_1 $date_file_1
touch -t $filter_param_2 $date_file_2
filter_matched=`find $repository -newer $date_file_1 \! -newer $date_file_2 -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_bigger_than() {
assert_not_null $filter_param_1 $filter
filter_matched=`find $repository -size +${filter_param_1}c -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_smaller_than() {
assert_not_null $filter_param_1 $filter
filter_matched=`find $repository -size -${filter_param_1}c -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_words() {
assert_not_null $filter_param_1 $filter
filter_matched=`grep -rlEw $filter_param_1 $repository`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_namefilter() {
assert_not_null $filter_param_1 $filter
filter_matched=`find $repository -regextype posix-extended -regex '^.*/[^\/]*(${filter_param_1})[^\/]*$' -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_keep_total_size_under() {
assert_not_null $filter_param_1 $filter
local allfiles=`find $repository -size +1c -type f -printf %h/%f:%s\\\n | sort -rn -t \: -k 2`
local currentsize=0
local maxsize=$(($filter_param_1-1))
local delete_all='false'
for a in $allfiles ; do
if [ '${delete_all}' == 'true' ] ; then
rm -f `echo $a | cut -d \: -f 1` &> /dev/null
continue
fi
currentsize=$(($currentsize+`echo $a | cut -d \: -f 2`))
if [ $currentsize -gt $maxsize ] ; then
rm -f `echo $a | cut -d \: -f 1` &> /dev/null
delete_all='true'
fi
done
}
- Эдгээр функцүүдийн ихэнх нь Лаб #3, Лаб #4 -с хуулагдсан. Гэхдээ заримд нь бага зэргийн өөрчлөлтүүд хэрэгтэй.
- filter_namefilter() функц нэлээн сонирхолтой. Энэ тохиолдолд find -ийн анхдагч энгийн илэрхийллийн боловсруулагч нь тохиромжгүй байна. Бидэнд ЗӨВХӨН нэр нь таарсан файлууд л хэрэгтэй учраас 'өргөтгөгдсөн' төрлийн энгийн илэрхийлэл шаардлагатай байна. Дээр байгаа энгийн илэрхийлэл ^.*/[^\/]*(${filter_param_1})[^\/]*$ нь 'эхлэлээс хамгийн сүүлийн '/' хүртэл дурын тэмдэгтийг тааруулaaд (match) , бүтэн замын үлдсэн хэсгийг хэрэглэгчийн оруулсан зүйлийн дагуу тааруул' гэсэн үг юм.
- Мөн хэдэн нийтлэг функцийг нэмсэн байгаа:
- check_date_format() : параметр нь зөв эсэхийг шалгах -- $date_format -ын дагуу байх ёстой.
- assert_no_more_param(): өөр ямар нэгэн параметр үлдээгүй эсэхийг шалгах, хэрэв үлдсэн бол мэдээлэл гаргаад програмыг дуусгах.
- assert_not_null(): хувьсагч null биш эсэхийг шалгах, үгүй бол алдааны мэдээлэл гаргаад програмыг дуусгах.
- assert_last_cmd_success(): сүүлийн команд алдаагүй ажилласан эсэхийг шалгах (0-с бага биш), үгүй бол алдааны мэдээлэл гаргаад програмыг дуусгах.
- dispatch_action(): өөр нэгэн зохицуулагч маягаар ашиглагдах энэ функц нь 'үйлдэл'-д тохирох функцийг дуудах болно. Энэ функц мөн 'үйлдэл'-д шаардлагатай аргументуудыг тодорхойлох болно.
Алхам #4 - Үндсэн 'зохицуулагч'-ийг дуудах
- source: ~/sw302/lab05/ufa.sh
# main filter dispatcher
case '${filter}' in
'--help')
usage
;;
'--older_than' | '--newer_than')
check_date_format $2
shift 2
;;
'--date_between')
check_date_format $2
# we need to retain the first date since check_date_format always
# write to variable filter_param_1
tmp=$filter_param_1
check_date_format $3
filter_param_2=$filter_param_1
filter_param_1=$tmp
shift 3
;;
'--bigger_than' | '--smaller_than')
filter_param_1=$2
shift 2
;;
'--words' | '--namefilter')
shift 1
fetch_and_shift_args $*
shift $filter_param_count
;;
'--keep_total_size_under')
filter_param_1=$2
shift 2
;;
*)
usage
;;
esac
# make sure that --keep_total_size_under has no more than 1 parameter.
if [ '${filter}' == '--keep_total_size_under' ] ; then
assert_no_more_param $*
else
action=$1
shift 1
fi
# invoking the filter function. The function name is the same as removing
# the first two '--' from $filter variable.
result='`filter_${filter##--} $*`'
echo '${result:=''}'
case '${filter}' in
'--help')
usage
;;
'--older_than' | '--newer_than')
check_date_format $2
shift 2
;;
'--date_between')
check_date_format $2
# we need to retain the first date since check_date_format always
# write to variable filter_param_1
tmp=$filter_param_1
check_date_format $3
filter_param_2=$filter_param_1
filter_param_1=$tmp
shift 3
;;
'--bigger_than' | '--smaller_than')
filter_param_1=$2
shift 2
;;
'--words' | '--namefilter')
shift 1
fetch_and_shift_args $*
shift $filter_param_count
;;
'--keep_total_size_under')
filter_param_1=$2
shift 2
;;
*)
usage
;;
esac
# make sure that --keep_total_size_under has no more than 1 parameter.
if [ '${filter}' == '--keep_total_size_under' ] ; then
assert_no_more_param $*
else
action=$1
shift 1
fi
# invoking the filter function. The function name is the same as removing
# the first two '--' from $filter variable.
result='`filter_${filter##--} $*`'
echo '${result:=''}'
- Үндсэн 'зохицуулагч'-ийг илүү үр дүнтэй ажилладаг болгож өөрчлөнө. Хэрэв илүү ажиглавал, зарим 'шүүлтүүр' нь хоорондоо төстэй байгаа. Тиймээс бид тэдгээрийг бүлэглэж болно -- жишээ нь ('--older_than' | '--newer_than').
- Мөн 'шүүлтүүр' функцийг илүү автоматаар дууддаг болгож болно. Жишээ нь: '--older_than' нь 'filter_older_than' функцийг дуудна. Хэрэв бид '--' -г '--older_than' -с хасаад 'filter_' -г урд нь залгаж орхивол 'filter_older_than' буюу дуудах функцийн нэр нь гарч ирнэ -- `filter_${filter##--} ...`
- Командын мөрийн аргументуудыг shift командыг ашиглан гүйлгэж болдог. Үүнийг ашигласнаар уншихад амархан байдаг. $1 нь $0, $2 нь $1, ... болно.
Алхам #5 - Нийтлэг функцүүд
- source: ~/sw302/lab05/ufa.sh
# check that $1 has the correct date format -- must conformed to $date_format
function check_date_format() {
if [ '${1}' == '' ] ; then
echo 'Error! Invalid date format : empty'
exit $?
fi
# try change $1 to the proper date format
filter_param_1=`date -d '${1}' +$date_format 2> /dev/null`
if [ $? != 0 ] ; then
echo 'Error! Invalid date format : ${1}'
exit $?
fi
}
# make sure that there is no more parameters to parse
function assert_no_more_param() {
if [ '${*}' != '' ] ; then
echo 'Unexpected commandline parameters: ${*}'
exit $ec_unexpected_param
fi
}
# make sure that the parameter ($1) is not null.
function assert_not_null() {
if [ '$1' == '' ] ; then
echo 'A valid parameter is expected for $2'
exit $ec_bad_param
fi
}
# make sure that the last command run successfully (i.e. without any exit
# code less than 0)
function assert_last_cmd_success() {
if [ $1 != 0 ]; then
echo 'Your filter command ($filter) failed'
exit $ec_failed_command
fi
}
# this function determine the parameter(s) needed for a function, as well
# as invoking the function itself.
function dispatch_action() {
# sanity check
if [ '${filter_matched}' = '' ] ; then
echo No files matched
exit 0
fi
# take care of default action
if [ '${action}' == '' ] ; then
action='--list'
fi
case '${action}' in
'--delete' | '--list' | '--list_detail')
assert_no_more_param $*
;;
'--replace' | '--newrepository')
action_param_1=$1
shift 1
assert_no_more_param $*
;;
*)
usage
;;
esac
# invoking the function. The function name is the same as removing
# the first two '--' from $action variable.
action_result='`action_${action##--} $*`'
echo '${action_result:=''}'
}
* dispatch_action() функц нь 'dispatcher' -тэй төстэй ажиллана.
Алхам #6 - 'үйлдэл' функцүүд
* source: ~/sw302/lab05/ufa.sh
function action_list() {
for a in ${filter_matched} ; do
echo $a
done
}
function action_list_detail() {
for a in ${filter_matched} ; do
find $repository -wholename '$a' -printf %h/%f\\t%s\\t%TY-%Tm-%Td\ %TH:%Tm:%TS\\n
done
}
function action_delete() {
for a in $filter_matched ; do
rm $a &> /dev/null
assert_last_cmd_success $?
done
}
function action_replace() {
# sanity check
if [ '${filter}' != '--words' ] ; then
echo '--replace is only valid when used with --words'
exit $ec_bad_command
fi
assert_not_null $action_param_1 $action
for a in $filter_matched ; do
sed -ire 's/${filter_param_1}/${action_param_1}/g' $a
assert_last_cmd_success $?
done
}
function action_newrepository {
# first we'll collect all the matched file into $tmp_file
local tmp_file='.tmp.newrepository.lst'
for a in $filter_matched ; do
echo $a >> $tmp_file
done
# use $tmp_file to instruct tar command to create tar.gz file
tar -zc -T $tmp_file 1> $action_param_1 2> /dev/null
# now we should store the outcome of the previous command, because
# when we execute the next command (rm -fR ...), the $? value would
# be changed.
local tar_ec=$?
rm -fR $tmp_file &> /dev/null
assert_last_cmd_success $tar_ec
}
function check_date_format() {
if [ '${1}' == '' ] ; then
echo 'Error! Invalid date format : empty'
exit $?
fi
# try change $1 to the proper date format
filter_param_1=`date -d '${1}' +$date_format 2> /dev/null`
if [ $? != 0 ] ; then
echo 'Error! Invalid date format : ${1}'
exit $?
fi
}
# make sure that there is no more parameters to parse
function assert_no_more_param() {
if [ '${*}' != '' ] ; then
echo 'Unexpected commandline parameters: ${*}'
exit $ec_unexpected_param
fi
}
# make sure that the parameter ($1) is not null.
function assert_not_null() {
if [ '$1' == '' ] ; then
echo 'A valid parameter is expected for $2'
exit $ec_bad_param
fi
}
# make sure that the last command run successfully (i.e. without any exit
# code less than 0)
function assert_last_cmd_success() {
if [ $1 != 0 ]; then
echo 'Your filter command ($filter) failed'
exit $ec_failed_command
fi
}
# this function determine the parameter(s) needed for a function, as well
# as invoking the function itself.
function dispatch_action() {
# sanity check
if [ '${filter_matched}' = '' ] ; then
echo No files matched
exit 0
fi
# take care of default action
if [ '${action}' == '' ] ; then
action='--list'
fi
case '${action}' in
'--delete' | '--list' | '--list_detail')
assert_no_more_param $*
;;
'--replace' | '--newrepository')
action_param_1=$1
shift 1
assert_no_more_param $*
;;
*)
usage
;;
esac
# invoking the function. The function name is the same as removing
# the first two '--' from $action variable.
action_result='`action_${action##--} $*`'
echo '${action_result:=''}'
}
* dispatch_action() функц нь 'dispatcher' -тэй төстэй ажиллана.
Алхам #6 - 'үйлдэл' функцүүд
* source: ~/sw302/lab05/ufa.sh
function action_list() {
for a in ${filter_matched} ; do
echo $a
done
}
function action_list_detail() {
for a in ${filter_matched} ; do
find $repository -wholename '$a' -printf %h/%f\\t%s\\t%TY-%Tm-%Td\ %TH:%Tm:%TS\\n
done
}
function action_delete() {
for a in $filter_matched ; do
rm $a &> /dev/null
assert_last_cmd_success $?
done
}
function action_replace() {
# sanity check
if [ '${filter}' != '--words' ] ; then
echo '--replace is only valid when used with --words'
exit $ec_bad_command
fi
assert_not_null $action_param_1 $action
for a in $filter_matched ; do
sed -ire 's/${filter_param_1}/${action_param_1}/g' $a
assert_last_cmd_success $?
done
}
function action_newrepository {
# first we'll collect all the matched file into $tmp_file
local tmp_file='.tmp.newrepository.lst'
for a in $filter_matched ; do
echo $a >> $tmp_file
done
# use $tmp_file to instruct tar command to create tar.gz file
tar -zc -T $tmp_file 1> $action_param_1 2> /dev/null
# now we should store the outcome of the previous command, because
# when we execute the next command (rm -fR ...), the $? value would
# be changed.
local tar_ec=$?
rm -fR $tmp_file &> /dev/null
assert_last_cmd_success $tar_ec
}
- Эдгээр функцүүдийн ихэнх нь чамд ойлгомжтой байгаа байх. Гэхдээ би action_newrepository() функцийг тайлбарлая. Эхлээд бүх тохирсон файлуудыг түр зуурын файл ($tmp_file) руу хадгална. Дараа нь бид tar командаар .tar.gz үүсгэж энэ файлыг илгээнэ. Одоо бид түр зуурын файлаа устгаж орчноо цэвэрлэж болно. Гэхдээ tar командыг амжилттай ажилласан эсэхийг шалгахын тулд эхлээд буцаасан төлвийг хадгалах хэрэгтэй. $? локаль хувьсагч руу хадгалаад түр зуурын файлаа устгаад assert_last_cmd_success -г дуудна.
Скрипт бүхлээрээ
- source: ~/sw302/lab05/ufa.sh
#!/bin/bash
#----functions start------------------------------------------------------------
function usage() {
echo -e '\
`basename $0`: Invalid command!
GET HELP:
ufa.sh [ --help ]
FILTER & ACTION:
ufa.sh [ [ --older_than | --newer_than ] date | --date_between date1 date2 ] --|
[ ( --bigger_than | --smaller_than ) file_size_in_byte ] |--> FILTER
[ --words words ... | --namefilter filenames_filters ... ] --|
[ --delete ] --|
[ --list ] |
[ --list_detail ] |--> ACTION
[ --replace replace_word ] |
[ --newrepository repository_name_tar.gz ] --|
TRIM:
ufa.sh [ --keep_total_size_under total_repository_size_in_bytes ] |--> TRIM REPOSITORY'
exit $ec_bad_command
}
# check that $1 has the correct date format -- must conformed to $date_format
function check_date_format() {
if [ '${1}' == '' ] ; then
echo 'Error! Invalid date format : empty'
exit $?
fi
# try change $1 to the proper date format
filter_param_1=`date -d '${1}' +$date_format 2> /dev/null`
if [ $? != 0 ] ; then
echo 'Error! Invalid date format : ${1}'
exit $?
fi
}
# make sure that there is no more parameters to parse
function assert_no_more_param() {
if [ '${*}' != '' ] ; then
echo 'Unexpected commandline parameters: ${*}'
exit $ec_unexpected_param
fi
}
# make sure that the parameter ($1) is not null.
function assert_not_null() {
if [ '$1' == '' ] ; then
echo 'A valid parameter is expected for $2'
exit $ec_bad_param
fi
}
# make sure that the last command run successfully (i.e. without any exit
# code less than 0)
function assert_last_cmd_success() {
if [ $1 != 0 ]; then
echo 'Your filter command ($filter) failed'
exit $ec_failed_command
fi
}
# get all the commandline parameters until we reach a parameter that starts
# with '--'. The collected parameters are reformatted to the 'arg1|arg2'
# format for regex processing. In addition, the number of parameters
# collected will be stored in $filter_param_count variable.
# For example, 'a b c d e --f' will cause this function to gather the
# first 5 parameters as 'a|b\c|d|e' and $filter_param_count = 5.
function fetch_and_shift_args() {
local params=''
filter_param_count=0
for a in $* ; do
# test if $a starts with --
local b=${a#--}
if [ '${a}' = '${b}' ] ; then
# not a command, we'll use this as a parameters
filter_param_count=$(($filter_param_count+1))
# concatenate params with the 'arg1|arg2|arg3' format
if [ '${params}' == '' ] ; then
params=$a
else
params='${params}|$a'
fi
else
# found a command, quit now
break;
fi
done
filter_param_1='$params'
}
# this function determine the parameter(s) needed for a function, as well
# as invoking the function itself.
function dispatch_action() {
# sanity check
if [ '${filter_matched}' = '' ] ; then
echo No files matched
exit 0
fi
# take care of default action
if [ '${action}' == '' ] ; then
action='--list'
fi
case '${action}' in
'--delete' | '--list' | '--list_detail')
assert_no_more_param $*
;;
'--replace' | '--newrepository')
action_param_1=$1
shift 1
assert_no_more_param $*
;;
*)
usage
;;
esac
# invoking the function. The function name is the same as removing
# the first two '--' from $action variable.
action_result='`action_${action##--} $*`'
echo '${action_result:=''}'
}
function filter_older_than() {
assert_not_null $filter_param_1 $filter
touch -t $filter_param_1 $date_file_1
filter_matched=`find $repository \! -newer $date_file_1 -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_newer_than() {
assert_not_null $filter_param_1 $filter
touch -t $filter_param_1 $date_file_1
filter_matched=`find $repository -newer $date_file_1 -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_date_between() {
assert_not_null $filter_param_1 $filter
assert_not_null $filter_param_2 $filter
touch -t $filter_param_1 $date_file_1
touch -t $filter_param_2 $date_file_2
filter_matched=`find $repository -newer $date_file_1 \! -newer$date_file_2 -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_bigger_than() {
assert_not_null $filter_param_1 $filter
filter_matched=`find $repository -size +${filter_param_1}c -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_smaller_than() {
assert_not_null $filter_param_1 $filter
filter_matched=`find $repository -size -${filter_param_1}c -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_words() {
assert_not_null $filter_param_1 $filter
filter_matched=`grep -rlEw $filter_param_1 $repository`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_namefilter() {
assert_not_null $filter_param_1 $filter
filter_matched=`find $repository -regextype posix-extended -regex '^.*/[^\/]*(${filter_param_1})[^\/]*$' -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_keep_total_size_under() {
assert_not_null $filter_param_1 $filter
local allfiles=`find $repository -size +1c -type f -printf %h/%f:%s\\\n |sort -rn -t \: -k 2`
local currentsize=0
local maxsize=$(($filter_param_1-1))
local delete_all='false'
for a in $allfiles ; do
if [ '${delete_all}' == 'true' ] ; then
rm -f `echo $a | cut -d \: -f 1` &> /dev/null
continue
fi
currentsize=$(($currentsize+`echo $a | cut -d \: -f 2`))
if [ $currentsize -gt $maxsize ] ; then
rm -f `echo $a | cut -d \: -f 1` &> /dev/null
delete_all='true'
fi
done
}
# default action
function action_list() {
for a in ${filter_matched} ; do
echo $a
done
}
# print detail of each matched file.
function action_list_detail() {
for a in ${filter_matched} ; do
find $repository -wholename '$a' -printf %h/%f\\t%s\\t%TY-%Tm-%Td\ %TH:%Tm:%TS\\n
done
}
function action_delete() {
for a in $filter_matched ; do
rm $a &> /dev/null
assert_last_cmd_success $?
done
}
function action_replace() {
# sanity check
if [ '${filter}' != '--words' ] ; then
echo '--replace is only valid when used with --words'
exit $ec_bad_command
fi
assert_not_null $action_param_1 $action
for a in $filter_matched ; do
sed -ire 's/${filter_param_1}/${action_param_1}/g' $a
assert_last_cmd_success $?
done
}
# put all matched files into a tar.gz file
function action_newrepository {
# first we'll collect all the matched file into $tmp_file
local tmp_file='.tmp.newrepository.lst'
for a in $filter_matched ; do
echo $a >> $tmp_file
done
# use $tmp_file to instruct tar command to create tar.gz file
tar -zc -T $tmp_file 1> $action_param_1 2> /dev/null
# now we should store the outcome of the previous command, because
# when we execute the next command (rm -fR ...), the $? value would
# be changed.
local tar_ec=$?
rm -fR $tmp_file &> /dev/null
assert_last_cmd_success $tar_ec
}
#----functions end--------------------------------------------------------------
# sanity check
if [ $# = 0 ] ; then usage; fi
# exit status
ec_bad_command=-1
ec_no_match=-2
ec_unexpected_param=-3
ec_failed_command=-4
ec_bad_param=-5
# setup :- defaults
repository=~/sw302/lab05/repository
date_format=%Y%m%d%H%M.%S
date_file_1=.junk1
date_file_2=.junk2
# setup :- variables for filter
filter=$1
filter_param_1=''
filter_param_2=''
filter_param_count=0
filter_matched=''
# setup :- variables for action
action=''
action_param_1=''
# main filter dispatcher
case '${filter}' in
'--help')
usage
;;
'--older_than' | '--newer_than')
check_date_format $2
shift 2
;;
'--date_between')
check_date_format $2
# we need to retain the first date since check_date_format always
# write to variable filter_param_1
tmp=$filter_param_1
check_date_format $3
filter_param_2=$filter_param_1
filter_param_1=$tmp
shift 3
;;
'--bigger_than' | '--smaller_than')
filter_param_1=$2
shift 2
;;
'--words' | '--namefilter')
shift 1
fetch_and_shift_args $*
shift $filter_param_count
;;
'--keep_total_size_under')
filter_param_1=$2
shift 2
;;
*)
usage
;;
esac
# make sure that --keep_total_size_under has no more than 1 parameter.
if [ '${filter}' == '--keep_total_size_under' ] ; then
assert_no_more_param $*
else
action=$1
shift 1
fi
# invoking the filter function. The function name is the same as removing
# the first two '--' from $filter variable.
result='`filter_${filter##--} $*`'
echo '${result:=''}'
#----functions start------------------------------------------------------------
function usage() {
echo -e '\
`basename $0`: Invalid command!
GET HELP:
ufa.sh [ --help ]
FILTER & ACTION:
ufa.sh [ [ --older_than | --newer_than ] date | --date_between date1 date2 ] --|
[ ( --bigger_than | --smaller_than ) file_size_in_byte ] |--> FILTER
[ --words words ... | --namefilter filenames_filters ... ] --|
[ --delete ] --|
[ --list ] |
[ --list_detail ] |--> ACTION
[ --replace replace_word ] |
[ --newrepository repository_name_tar.gz ] --|
TRIM:
ufa.sh [ --keep_total_size_under total_repository_size_in_bytes ] |--> TRIM REPOSITORY'
exit $ec_bad_command
}
# check that $1 has the correct date format -- must conformed to $date_format
function check_date_format() {
if [ '${1}' == '' ] ; then
echo 'Error! Invalid date format : empty'
exit $?
fi
# try change $1 to the proper date format
filter_param_1=`date -d '${1}' +$date_format 2> /dev/null`
if [ $? != 0 ] ; then
echo 'Error! Invalid date format : ${1}'
exit $?
fi
}
# make sure that there is no more parameters to parse
function assert_no_more_param() {
if [ '${*}' != '' ] ; then
echo 'Unexpected commandline parameters: ${*}'
exit $ec_unexpected_param
fi
}
# make sure that the parameter ($1) is not null.
function assert_not_null() {
if [ '$1' == '' ] ; then
echo 'A valid parameter is expected for $2'
exit $ec_bad_param
fi
}
# make sure that the last command run successfully (i.e. without any exit
# code less than 0)
function assert_last_cmd_success() {
if [ $1 != 0 ]; then
echo 'Your filter command ($filter) failed'
exit $ec_failed_command
fi
}
# get all the commandline parameters until we reach a parameter that starts
# with '--'. The collected parameters are reformatted to the 'arg1|arg2'
# format for regex processing. In addition, the number of parameters
# collected will be stored in $filter_param_count variable.
# For example, 'a b c d e --f' will cause this function to gather the
# first 5 parameters as 'a|b\c|d|e' and $filter_param_count = 5.
function fetch_and_shift_args() {
local params=''
filter_param_count=0
for a in $* ; do
# test if $a starts with --
local b=${a#--}
if [ '${a}' = '${b}' ] ; then
# not a command, we'll use this as a parameters
filter_param_count=$(($filter_param_count+1))
# concatenate params with the 'arg1|arg2|arg3' format
if [ '${params}' == '' ] ; then
params=$a
else
params='${params}|$a'
fi
else
# found a command, quit now
break;
fi
done
filter_param_1='$params'
}
# this function determine the parameter(s) needed for a function, as well
# as invoking the function itself.
function dispatch_action() {
# sanity check
if [ '${filter_matched}' = '' ] ; then
echo No files matched
exit 0
fi
# take care of default action
if [ '${action}' == '' ] ; then
action='--list'
fi
case '${action}' in
'--delete' | '--list' | '--list_detail')
assert_no_more_param $*
;;
'--replace' | '--newrepository')
action_param_1=$1
shift 1
assert_no_more_param $*
;;
*)
usage
;;
esac
# invoking the function. The function name is the same as removing
# the first two '--' from $action variable.
action_result='`action_${action##--} $*`'
echo '${action_result:=''}'
}
function filter_older_than() {
assert_not_null $filter_param_1 $filter
touch -t $filter_param_1 $date_file_1
filter_matched=`find $repository \! -newer $date_file_1 -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_newer_than() {
assert_not_null $filter_param_1 $filter
touch -t $filter_param_1 $date_file_1
filter_matched=`find $repository -newer $date_file_1 -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_date_between() {
assert_not_null $filter_param_1 $filter
assert_not_null $filter_param_2 $filter
touch -t $filter_param_1 $date_file_1
touch -t $filter_param_2 $date_file_2
filter_matched=`find $repository -newer $date_file_1 \! -newer$date_file_2 -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_bigger_than() {
assert_not_null $filter_param_1 $filter
filter_matched=`find $repository -size +${filter_param_1}c -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_smaller_than() {
assert_not_null $filter_param_1 $filter
filter_matched=`find $repository -size -${filter_param_1}c -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_words() {
assert_not_null $filter_param_1 $filter
filter_matched=`grep -rlEw $filter_param_1 $repository`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_namefilter() {
assert_not_null $filter_param_1 $filter
filter_matched=`find $repository -regextype posix-extended -regex '^.*/[^\/]*(${filter_param_1})[^\/]*$' -type f -print`
assert_last_cmd_success $?
dispatch_action $*
}
function filter_keep_total_size_under() {
assert_not_null $filter_param_1 $filter
local allfiles=`find $repository -size +1c -type f -printf %h/%f:%s\\\n |sort -rn -t \: -k 2`
local currentsize=0
local maxsize=$(($filter_param_1-1))
local delete_all='false'
for a in $allfiles ; do
if [ '${delete_all}' == 'true' ] ; then
rm -f `echo $a | cut -d \: -f 1` &> /dev/null
continue
fi
currentsize=$(($currentsize+`echo $a | cut -d \: -f 2`))
if [ $currentsize -gt $maxsize ] ; then
rm -f `echo $a | cut -d \: -f 1` &> /dev/null
delete_all='true'
fi
done
}
# default action
function action_list() {
for a in ${filter_matched} ; do
echo $a
done
}
# print detail of each matched file.
function action_list_detail() {
for a in ${filter_matched} ; do
find $repository -wholename '$a' -printf %h/%f\\t%s\\t%TY-%Tm-%Td\ %TH:%Tm:%TS\\n
done
}
function action_delete() {
for a in $filter_matched ; do
rm $a &> /dev/null
assert_last_cmd_success $?
done
}
function action_replace() {
# sanity check
if [ '${filter}' != '--words' ] ; then
echo '--replace is only valid when used with --words'
exit $ec_bad_command
fi
assert_not_null $action_param_1 $action
for a in $filter_matched ; do
sed -ire 's/${filter_param_1}/${action_param_1}/g' $a
assert_last_cmd_success $?
done
}
# put all matched files into a tar.gz file
function action_newrepository {
# first we'll collect all the matched file into $tmp_file
local tmp_file='.tmp.newrepository.lst'
for a in $filter_matched ; do
echo $a >> $tmp_file
done
# use $tmp_file to instruct tar command to create tar.gz file
tar -zc -T $tmp_file 1> $action_param_1 2> /dev/null
# now we should store the outcome of the previous command, because
# when we execute the next command (rm -fR ...), the $? value would
# be changed.
local tar_ec=$?
rm -fR $tmp_file &> /dev/null
assert_last_cmd_success $tar_ec
}
#----functions end--------------------------------------------------------------
# sanity check
if [ $# = 0 ] ; then usage; fi
# exit status
ec_bad_command=-1
ec_no_match=-2
ec_unexpected_param=-3
ec_failed_command=-4
ec_bad_param=-5
# setup :- defaults
repository=~/sw302/lab05/repository
date_format=%Y%m%d%H%M.%S
date_file_1=.junk1
date_file_2=.junk2
# setup :- variables for filter
filter=$1
filter_param_1=''
filter_param_2=''
filter_param_count=0
filter_matched=''
# setup :- variables for action
action=''
action_param_1=''
# main filter dispatcher
case '${filter}' in
'--help')
usage
;;
'--older_than' | '--newer_than')
check_date_format $2
shift 2
;;
'--date_between')
check_date_format $2
# we need to retain the first date since check_date_format always
# write to variable filter_param_1
tmp=$filter_param_1
check_date_format $3
filter_param_2=$filter_param_1
filter_param_1=$tmp
shift 3
;;
'--bigger_than' | '--smaller_than')
filter_param_1=$2
shift 2
;;
'--words' | '--namefilter')
shift 1
fetch_and_shift_args $*
shift $filter_param_count
;;
'--keep_total_size_under')
filter_param_1=$2
shift 2
;;
*)
usage
;;
esac
# make sure that --keep_total_size_under has no more than 1 parameter.
if [ '${filter}' == '--keep_total_size_under' ] ; then
assert_no_more_param $*
else
action=$1
shift 1
fi
# invoking the filter function. The function name is the same as removing
# the first two '--' from $filter variable.
result='`filter_${filter##--} $*`'
echo '${result:=''}'
No comments:
Post a Comment