http://www.intuitive.com/wicked/wicked-cool-shell-script-library.shtml
先抄下来,后面有空慢慢加中文注释。
#!/bin/sh
# inpath - verify that a specified programis either valid as-is,
# or can be found in the PATH directory list.
in_path()
{
#given a command and the PATH, try to find the command. Returns
# 0if found and executable, 1 if not. Note that this temporarily modifies
#the IFS (input field seperator), but restores it upon completion.
cmd=$1 path=$2 retval=1
oldIFS=$IFS IFS=":"
fordirectory in $path
do
if [ -x $directory/$cmd ] ; then
retval=0 # if we're here, wefound $cmd in $directory
fi
done
IFS=$oldIFS
return $retval
}
checkForCmdInPath()
{
var=$1
#The variable slicing notation in the following conditional
#needs some explanation: ${var#expr} returns everything after
#the match for 'expr' in the variable value (if any), and
#${var%expr} returns everything that doesn't match (in this
#case just the very first character. You can also do this in
#Bash with ${var:0:1} and you could use cut too: cut -c1
if[ "$var" != "" ] ; then
if [ "${var%${var#?}}" ="/" ] ; then
if [ ! -x $var ] ; then
return 1
fi
elif ! in_path $var $PATH ; then
return 2
fi
fi
}
if [ $# -ne 1 ] ; then
echo"Usage: $0 command" >&2 ; exit 1
fi
checkForCmdInPath "$1"
case $? in
0 )echo "$1 found in PATH" ;;
1 )echo "$1 not found or not executable" ;;
2 )echo "$1 not found in PATH" ;;
esac
exit 0
#!/bin/sh
# validalAlphaNum - Ensures that input onlyconsists of alphabetical
# and numeric characters.
validAlphaNum()
{
#validate arg: returns 0 if all upper+lower+digits, 1 otherwise
#Remove all unacceptable chars
compressed="$(echo $1 | sed -e 's/[^[:alnum:]]//g')"
if[ "$compressed" != "$input" ] ; then
return 1
else
return 0
fi
}
# Sample usage of this function in a script
echo -n "Enter input: "
read input
if ! validAlphaNum "$input" ;then
echo "Your input must consist of only letters and numbers.">&2
exit 1
else
echo "Input is valid."
fi
exit 0
#!/bin/sh
# normdate - Normalizes month field in datespecification
# to three letters, first letter capitalized. A helper
# function for hack #7, validdate. Exits w/ zero if no error.
monthnoToName()
{
#sets the variable 'month' to the appropriate value
case $1 in
1) month="Jan" ;; 2 ) month="Feb" ;;
3) month="Mar" ;; 4 ) month="Apr" ;;
5) month="May" ;; 6 ) month="Jun" ;;
7) month="Jul" ;; 8 ) month="Aug" ;;
9) month="Sep" ;; 10) month="Oct" ;;
11) month="Nov" ;; 12) month="Dec" ;;
*) echo "$0: Unknown numeric month value $1" >&2; exit 1
esac
return 0
}
## Begin main script
if [ $# -eq 1 ] ; then # try to compensate for / or - formats
set-- $(echo $1 | sed 's/[\/\-]/ /g')
fi
if [ $# -ne 3 ] ; then
echo "Usage: $0 month day year" >&2
echo "Typical input formats are August 3 1962 and 8 3 2002">&2
exit 1
fi
if [ $3 -lt 99 ] ; then
echo"$0: expected four-digit year value." >&2; exit 1
fi
if [ -z $(echo $1|sed 's/[[:digit:]]//g')]; then
monthnoToName $1
else
#normalize to first three letters, first upper, rest lowercase
month="$(echo $1|cut -c1|tr '[:lower:]' '[:upper:]')"
month="$month$(echo $1|cut -c2-3 | tr '[:upper:]' '[:lower:]')"
fi
echo $month $2 $3
exit 0
#!/bin/sh
# nicenumber - given a number, show it withcomma separated values
# expects DD and TD to be instantiated. instantiates nicenum
# or, if a second arg is specified, the output is echoed to stdout
nicenumber()
{
#Note that we use the '.' as the decimal separator for parsing
#the INPUT value to this script. The output value is as specified
#by the user with the -d flag, if different from a '.'
integer=$(echo $1 | cut -d. -f1) #left of the decimal
decimal=$(echo $1 | cut -d. -f2) #right of the decimal
if[ $decimal != $1 ]; then
#there's a fractional part, let's include it.
result="${DD:="."}$decimal"
fi
thousands=$integer
while [ $thousands -gt 999 ]; do
remainder=$(($thousands % 1000)) #three least significant digits
while [ ${#remainder} -lt 3 ] ; do #force leading zeroes as needed
remainder="0$remainder"
done
thousands=$(($thousands / 1000)) #to left of remainder, if any
result="${TD:=","}${remainder}${result}" # builds right-to-left
done
nicenum="${thousands}${result}"
if[ ! -z $2 ] ; then
echo $nicenum
fi
}
DD="." # decimal point delimiter, between integer & fractionalvalue
TD="," # thousands delimiter, separates every three digits
while getopts "d:t:" opt; do
case $opt in
d) DD="$OPTARG" ;;
t) TD="$OPTARG" ;;
esac
done
shift $(($OPTIND - 1))
if [ $# -eq 0 ] ; then
cat<< "EOF" >&2
Usage: $(basename $0) [-d c] [-t c] numericvalue
-d specifies the decimal point delimiter (default '.')
-t specifies the thousands delimiter (default ',')
EOF
exit 1
fi
nicenumber $1 1 # second arg forces this to 'echo' output
exit 0
#!/bin/sh
# validint - validate integer input, allownegative ints too
validint()
{
#validate first field. Optionally test against min value $2 and/or
#max value $3: if you'd rather skip these tests, send "" as values.
#returns 1 for error, 0 for success.
number="$1"; min="$2"; max="$3"
if[ -z $number ] ; then
echo "You didn't enter anything. Unacceptable." >&2 ;return 1
fi
if[ "${number%${number#?}}" = "-" ] ; then # first char '-' ?
testvalue="${number#?}" #all but first character
else
testvalue="$number"
fi
nodigits="$(echo $testvalue | sed 's/[[:digit:]]//g')"
if[ ! -z $nodigits ] ; then
echo "Invalid number format! Only digits, no commas, spaces,etc." >&2
return 1
fi
if[ ! -z $min ] ; then
if [ "$number" -lt "$min" ] ; then
echo "Your value is too small: smallest acceptable value is$min" >&2
return 1
fi
fi
if[ ! -z $max ] ; then
if [ "$number" -gt "$max" ] ; then
echo "Your value is too big: largest acceptable value is $max">&2
return 1
fi
fi
return 0
}
# uncomment these lines to test, but bewarethat it'll break Hack #6
# because Hack #6 wants to source this fileto get the validint()
# function. :-)
# if validint "$1" "$2""$3" ; then
# echo "That input is a valid integer value within yourconstraints"
# fi
#!/bin/sh
# validfloat - test whether a number is avalid floating point value.
# Note that this cannot accept scientific (1.304e5) notation.
# To test whether an entered value is avalid floating point number, we
# need to split the value at the decimalpoint, then test the first part
# to see if it's a valid integer, then thesecond part to see if it's a
# valid >=0 integer, so -30.5 is valid,but -30.-8 isn't.
. 005-validint.sh # source the validint function
validfloat()
{
fvalue="$1"
if[ ! -z $(echo $fvalue | sed 's/[^.]//g') ] ; then
decimalPart="$(echo $fvalue | cut -d. -f1)"
fractionalPart="$(echo $fvalue | cut -d. -f2)"
if [ ! -z $decimalPart ] ; then
if ! validint "$decimalPart" "" "" ; then
return 1
fi
fi
if [ "${fractionalPart%${fractionalPart#?}}" = "-" ]; then
echo "Invalid floating point number: '-' not allowed \
afterdecimal point" >&2
return 1
fi
if [ "$fractionalPart" != "" ] ; then
if ! validint "$fractionalPart" "0" "" ;then
return 1
fi
fi
if [ "$decimalPart" = "-" -o -z $decimalPart ] ;then
if [ -z $fractionalPart ] ; then
echo "Invalid floating point format." >&2 ; return 1
fi
fi
else
if [ "$fvalue" = "-" ] ; then
echo "Invalid floating point format." >&2 ; return 1
fi
if ! validint "$fvalue" "" "" ; then
return 1
fi
fi
return 0
}
if validfloat $1 ; then
echo "$1 is a valid floating point value"
fi
exit 0
#!/bin/sh
# valid-date - validate date, taking intoaccount leap year rules
normdate="./003-normdate.sh" # hack #3 for normalizing month name
exceedsDaysInMonth()
{
#given a month name, return 0 if the specified day value is
#less than or equal to the max days in the month, 1 otherwise
case $(echo $1|tr '[:upper:]' '[:lower:]') in
jan* ) days=31 ;; feb* ) days=28 ;;
mar* ) days=31 ;; apr* ) days=30 ;;
may* ) days=31 ;; jun* ) days=30 ;;
jul* ) days=31 ;; aug* ) days=31 ;;
sep* ) days=30 ;; oct* ) days=31 ;;
nov* ) days=30 ;; dec* ) days=31 ;;
*) echo "$0: Unknown month name $1" >&2; exit 1
esac
if[ $2 -lt 1 -o $2 -gt $days ] ; then
return 1
else
return 0 # all is well
fi
}
isLeapYear()
{
#this function returns 0 if a leap year, 1 otherwise
#The formula for checking whether a year is a leap year is:
#1. years divisible by four are leap years, unless..
#2. years also divisible by 100 are not leap years, except...
#3. years divisible by 400 are leap years
year=$1
if[ "$((year % 4))" -ne 0 ] ; then
return 1 # nope, not a leap year
elif [ "$((year % 400))" -eq 0 ] ; then
return 0 # yes, it's a leap year
elif [ "$((year % 100))" -eq 0 ] ; then
return 1
else
return 0
fi
}
## Begin main script
if [ $# -ne 3 ] ; then
echo "Usage: $0 month day year" >&2
echo "Typical input formats are August 3 1962 and 8 3 2002">&2
exit 1
fi
# normalize date and split back outreturned values
newdate="$($normdate"$@")"
if [ $? -eq 1 ] ; then
exit 1 # error condition alreadyreported by normdate
fi
month="$(echo $newdate | cut -d\ -f1)"
day="$(echo $newdate | cut -d\ -f2)"
year="$(echo $newdate | cut -d\ -f3)"
# Now that we have a normalized date, let'scheck to see if the
# day value is logical
if ! exceedsDaysInMonth $month"$2" ; then
if[ "$month" = "Feb" -a $2 -eq 29 ] ; then
if ! isLeapYear $3 ; then
echo "$0: $3 is not a leap year, so Feb doesn't have 29 days">&2
exit 1
fi
else
echo "$0: bad day value: $month doesn't have $2 days">&2
exit 1
fi
fi
echo "Valid date: $newdate"
exit 0
#!/bin/sh
# echon - a script to emulate the -n flagfunctionality with 'echo'
# for Unix systems that don't have that available.
echon()
{
echo "$*" | tr -d '\n'
}
echon "this is a test: "
read answer
echon this is a test too " "
read answer2
#!/bin/sh
# echon - a script to emulate the -n flagfunctionality with 'echo'
# for Unix systems that don't have that available.
echon()
{
echo "$*" | tr -d '\n'
}
echon "this is a test: "
read answer
echon this is a test too " "
read answer2
#!/bin/sh
# echon - a script to emulate the -n flagfunctionality with 'echo'
# for Unix systems that don't have that available.
echon()
{
echo "$*" | tr -d '\n'
}
echon "this is a test: "
read answer
echon this is a test too " "
read answer2
#!/bin/sh
# ANSI Color -- use these variables toeasily have different color
# and format output. Make sure to output the reset sequence after
# colors (f = foreground, b = background), and use the 'off'
# feature for anything you turn on.
initializeANSI()
{
esc=""
blackf="${esc}[30m"; redf="${esc}[31m"; greenf="${esc}[32m"
yellowf="${esc}[33m" bluef="${esc}[34m"; purplef="${esc}[35m"
cyanf="${esc}[36m"; whitef="${esc}[37m"
blackb="${esc}[40m"; redb="${esc}[41m"; greenb="${esc}[42m"
yellowb="${esc}[43m" blueb="${esc}[44m"; purpleb="${esc}[45m"
cyanb="${esc}[46m"; whiteb="${esc}[47m"
boldon="${esc}[1m"; boldoff="${esc}[22m"
italicson="${esc}[3m"; italicsoff="${esc}[23m"
ulon="${esc}[4m"; uloff="${esc}[24m"
invon="${esc}[7m"; invoff="${esc}[27m"
reset="${esc}[0m"
}
# note in this first use that switchingcolors doesn't require a reset
# first - the new color overrides the oldone.
initializeANSI
cat << EOF
${yellowf}This is a phrase in yellow${redb}and red${reset}
${boldon}This is bold${ulon} this isitalics${reset} bye bye
${italicson}This is italics${italicsoff}and this is not
${ulon}This is ul${uloff} and this is not
${invon}This is inv${invoff} and this isnot
${yellowf}${redb}WarningI${yellowb}${redf}Warning II${reset}
EOF
#!/bin/sh
# Script to demonstrate use of the shellfunction library
. 012-library.sh
initializeANSI
echon "First off, do you have echo inyour path? (1=yes, 2=no) "
read answer
while ! validint $answer 1 2 ; do
echon "${boldon}Try again${boldoff}. Do you have echo "
echon "in your path? (1=yes, 2=no) "
read answer
done
if ! checkForCmdInPath "echo" ;then
echo "Nope, can't find the echo command."
else
echo "The echo command is in the PATH."
fi
echo ""
echon "Enter a year you think might bea leap year: "
read year
while ! validint $year 1 9999 ; do
echon "Please enter a year in the ${boldon}correct${boldoff}format: "
read year
done
if isLeapYear $year ; then
echo "${greenf}You're right! $year was a leap year.${reset}"
else
echo "${redf}Nope, that's not a leap year.${reset}"
fi
exit 0
#!/bin/sh
# inpath - verify that a specified programis either valid as-is,
# or can be found in the PATH directory list.
in_path()
{
#given a command and the PATH, try to find the command. Returns
# 0if found and executable, 1 if not. Note that this temporarily modifies
#the the IFS (input field seperator), but restores it upon completion.
#return variable 'directory' contains the directory where the
#command was found.
cmd=$1 path=$2 retval=1
oldIFS=$IFS IFS=":"
fordirectory in $path
do
if [ -x $directory/$cmd ] ; then
retval=0 # if we're here, wefound $cmd in $directory
fi
done
IFS=$oldIFS
return $retval
}
checkForCmdInPath()
{
var=$1
#The variable slicing notation in the following conditional
#needs some explanation: ${var#expr} returns everything after
#the match for 'expr' in the variable value (if any), and
#${var%expr} returns everything that doesn't match (in this
#case just the very first character. You can also do this in
#Bash with ${var:0:1} and you could use cut too: cut -c1
if[ "$var" != "" ] ; then
if [ "${var%${var#?}}" = "/" ] ; then
if [ ! -x $var ] ; then
return 1
fi
elif ! in_path $var $PATH ; then
return 2
fi
fi
return 0
}
# cnvalidate - Ensures that input onlyconsists of alphabetical
# and numeric characters.
cnvalidate()
{
#validate arg: returns 0 if all upper+lower+digits, 1 otherwise
#Remove all unacceptable chars
compressed="$(echo $1 | sed -e 's/[^[:alnum:]]//g')"
if[ "$compressed" != "$input" ] ; then
return 1
else
return 0
fi
}
monthnoToName()
{
#sets the variable 'month' to the appropriate value
case $1 in
1) month="Jan" ;; 2 ) month="Feb" ;;
3) month="Mar" ;; 4 ) month="Apr" ;;
5) month="May" ;; 6 ) month="Jun" ;;
7) month="Jul" ;; 8 ) month="Aug" ;;
9) month="Sep" ;; 10) month="Oct" ;;
11) month="Nov" ;; 12) month="Dec" ;;
*) echo "$0: Unknown numeric month value $1" >&2; exit 1
esac
return 0
}
# nicenumber - given a number, show it withcomma separated values
# expects DD and TD to be instantiated. instantiates nicenum
# if arg2 is specified, this function echoes output, rather than
# sending it back as a variable
nicenumber()
{
#Note that we use the '.' as the decimal separator for parsing
#the INPUT value to this script. The output value is as specified
#by the user with the -d flag, if different from a '.'
integer=$(echo $1 | cut -d. -f1) #left of the decimal
decimal=$(echo $1 | cut -d. -f2) #right of the decimal
if[ $decimal != $1 ]; then
#there's a fractional part, let's include it.
result="${DD:="."}$decimal"
fi
thousands=$integer
while [ $thousands -gt 999 ]; do
remainder=$(($thousands % 1000)) #three least significant digits
while [ ${#remainder} -lt 3 ] ; do #force leading zeroes as needed
remainder="0$remainder"
done
thousands=$(($thousands / 1000)) #to left of remainder, if any
result="${TD:=","}${remainder}${result}" # builds right-to-left
done
nicenum="${thousands}${result}"
if[ ! -z $2 ] ; then
echo $nicenum
fi
}
# validint - validate integer input, allownegative ints too
validint()
{
#validate first field. Optionally test against min value $2 and/or
#max value $3: if you'd rather skip these tests, send "" as values.
#returns 1 for error, 0 for success
number="$1"; min="$2"; max="$3"
if[ -z "$number" ] ; then
echo "You didn't enter anything. Unacceptable." >&2 ;return 1
fi
if[ "${number%${number#?}}" = "-" ] ; then # first char '-' ?
testvalue="${number#?}" #all but first character
else
testvalue="$number"
fi
nodigits="$(echo $testvalue | sed 's/[[:digit:]]//g')"
if[ ! -z "$nodigits" ] ; then
echo "Invalid number format! Only digits, no commas, spaces,etc." >&2
return 1
fi
if[ ! -z "$min" ] ; then
if [ "$number" -lt "$min" ] ; then
echo "Your value is too small: smallest acceptable value is$min" >&2
return 1
fi
fi
if[ ! -z "$max" ] ; then
if [ "$number" -gt "$max" ] ; then
echo "Your value is too big: largest acceptable value is $max">&2
return 1
fi
fi
return 0
}
# validfloat - test whether a number is avalid floating point value.
# Note that this cannot accept scientific (1.304e5) notation.
# To test whether an entered value is avalid floating point number, we
# need to split the value at the decimalpoint, then test the first part
# to see if it's a valid integer, then the secondpart to see if it's a
# valid >=0 integer, so -30.5 is valid,but -30.-8 isn't. Returns 0 on
# success, 1 on failure.
validfloat()
{
fvalue="$1"
if[ ! -z "$(echo $fvalue | sed 's/[^.]//g')" ] ; then
decimalPart="$(echo $fvalue | cut -d. -f1)"
fractionalPart="$(echo $fvalue | cut -d. -f2)"
if [ ! -z "$decimalPart" ] ; then
if ! validint "$decimalPart" "" "" ; then
return 1
fi
fi
if [ "${fractionalPart%${fractionalPart#?}}" = "-" ]; then
echo "Invalid floating point number:'-' not allowed \
after decimal point" >&2
return 1
fi
if [ "$fractionalPart" != "" ] ; then
if ! validint "$fractionalPart" "0" "" ;then
return 1
fi
fi
if [ "$decimalPart" = "-" -o -z"$decimalPart" ] ; then
if [ -z "$fractionalPart" ] ; then
echo "Invalid floating point format." >&2 ; return 1
fi
fi
else
if [ "$fvalue" = "-" ] ; then
echo "Invalid floating point format." >&2 ; return 1
fi
if ! validint "$fvalue" "" "" ; then
return 1
fi
fi
return 0
}
exceedsDaysInMonth()
{
#given a month name, return 0 if the specified day value is
#less than or equal to the max days in the month, 1 otherwise
case $(echo $1|tr '[:upper:]' '[:lower:]') in
jan* ) days=31 ;; feb* ) days=28 ;;
mar* ) days=31 ;; apr* ) days=30 ;;
may* ) days=31 ;; jun* ) days=30 ;;
jul* ) days=31 ;; aug* ) days=31 ;;
sep* ) days=30 ;; oct* ) days=31 ;;
nov* ) days=30 ;; dec* ) days=31 ;;
*) echo "$0: Unknown month name $1" >&2; exit 1
esac
if[ $2 -lt 1 -o $2 -gt $days ] ; then
return 1
else
return 0 # all is well
fi
}
isLeapYear()
{
#this function returns 0 if a leap year, 1 otherwise
#The formula for checking whether a year is a leap year is:
#1. years divisible by four are leap years, unless..
#2. years also divisible by 100 are not leap years, except...
#3. years divisible by 400 are leap years
year=$1
if[ "$((year % 4))" -ne 0 ] ; then
return 1 # nope, not a leap year
elif [ "$((year % 400))" -eq 0 ] ; then
return 0 # yes, it's a leap year
elif [ "$((year % 100))" -eq 0 ] ; then
return 1
else
return 0
fi
}
validdate()
{
#expects three values, month, day and year. Returns 0 if success.
newdate="$(normdate "$@")"
if[ $? -eq 1 ] ; then
exit 1 # error conditionalready reported by normdate
fi
month="$(echo $newdate | cut -d\ -f1)"
day="$(echo $newdate | cut -d\ -f2)"
year="$(echo $newdate | cut -d\ -f3)"
#Now that we have a normalized date, let's check to see if the
#day value is logical
if! exceedsDaysInMonth $month "$2" ; then
if [ "$month" = "Feb" -a $2 -eq 29 ] ; then
if ! isLeapYear $3 ; then
echo "$0: $3 is not a leap year, so Feb doesn't have 29 days">&2
exit 1
fi
else
echo "$0: bad day value: $month doesn't have $2 days">&2
exit 1
fi
fi
return 0
}
echon()
{
echo "$*" | tr -d '\n'
}
initializeANSI()
{
esc=""
blackf="${esc}[30m"; redf="${esc}[31m"; greenf="${esc}[32m"
yellowf="${esc}[33m" bluef="${esc}[34m"; purplef="${esc}[35m"
cyanf="${esc}[36m"; whitef="${esc}[37m"
blackb="${esc}[40m"; redb="${esc}[41m"; greenb="${esc}[42m"
yellowb="${esc}[43m" blueb="${esc}[44m"; purpleb="${esc}[45m"
cyanb="${esc}[46m"; whiteb="${esc}[47m"
boldon="${esc}[1m"; boldoff="${esc}[22m"
italicson="${esc}[3m"; italicsoff="${esc}[23m"
ulon="${esc}[4m"; uloff="${esc}[24m"
invon="${esc}[7m"; invoff="${esc}[27m"
reset="${esc}[0m"
}
#!/bin/sh
# hilow - a simple number guessing game
biggest=100 # maximum numberpossible
guess=0 # guessed byplayer
guesses=0 # number ofguesses made
number=$(( $$ % $biggest )) # random number, 1 .. $biggest
while [ $guess -ne $number ] ; do
echo -n "Guess? " ; read guess
if[ "$guess" -lt $number ] ; then
echo "... bigger!"
elif [ "$guess" -gt $number ] ; then
echo "... smaller!"
fi
guesses=$(( $guesses + 1 ))
done
echo "Right!! Guessed $number in$guesses guesses."
exit 0
#!/bin/sh
# nfmt - A version of fmt, using nroff.Adds two useful flags: -w X for
# line width and -h to enable hyphenationfor better fills.
while getopts "hw:" opt; do
case $opt in
h) hyph=1 ;;
w) width="$OPTARG" ;;
esac
done
shift $(($OPTIND - 1))
nroff << EOF
.ll ${width:-72}
.na
.hy ${hyph:-0}
.pl 1
$(cat "$@")
EOF
exit 0
#!/bin/sh
# newrm - a replacement for the existing rmcommand that allows a
# rudimentary unremove capability through utilizing a newly created
# directory in the user's home directory. It can handle directories
# of content as well as individual files, and if the user specifies
# the -f flag, files are NOT archived, but removed.
# Big Important Warning: you'll want a cronjob or similar to keep the
# individual trash directories tamed, otherwise nothing will ever
# actually be deleted on the system and you'll run out of disk space!
mydir="$HOME/.deleted-files"
realrm="/bin/rm "
copy="/bin/cp -R"
if [ $# -eq 0 ] ; then # let 'rm' ouptut the usage error
exec $realrm # our shelldies and is replaced by /bin/rm
fi
# parse all options looking for '-f'
flags=""
while getopts "dfiPRrvW" opt
do
case $opt in
f) exec $realrm "$@" ;; # exec lets us exit this script directly.
*) flags="$flags -$opt" ;; # other flags are for 'rm', not us
esac
done
shift $(( $OPTIND - 1 ))
# make sure that the $mydir exists
if [ ! -d $mydir ] ; then
if[ ! -w $HOME ] ; then
echo"$0 failed: can't create $mydir in $HOME" >&2
exit 1
fi
mkdir $mydir
chmod 700 $mydir # a littlebit of privacy, please
fi
for arg
do
newname="$mydir/$(date "+%S.%M.%H.%d.%m").$(basename"$arg")"
if[ -f "$arg" ] ; then
$copy "$arg" "$newname"
elif [ -d "$arg" ] ; then
$copy "$arg" "$newname"
fi
done
exec $realrm $flags "$@" # our shell is replaced by realrm
#!/bin/sh
# unrm - search the deleted files archivefor the specified file. If
# there is more than one match, show a list ordered by timestamp, and
# let the user specify which they want restored.
# Big Important Warning: you'll want a cronjob or similar to keep the
# individual trash directories tamed, otherwise nothing will ever
# actually be deleted on the system and you'll run out of disk space!
mydir="$HOME/.deleted-files"
realrm="/bin/rm"
move="/bin/mv"
dest=$(pwd)
if [ ! -d $mydir ] ; then
echo "$0: No deleted files directory: nothing to unrm">&2 ; exit 1
fi
cd $mydir
if [ $# -eq 0 ] ; then # no args, just showlisting
echo "Contents of your deleted files archive (sorted bydate):"
# ls-FC | sed -e 's/[[:digit:]][[:digit:]]\.//g' -e 's/^/ /'
ls-FC | sed -e 's/\([[:digit:]][[:digit:]]\.\)\{5\}//g' \
-e 's/^/ /'
exit0
fi
# Otherwise we must have a pattern to workwith. Let's see if the
# user-specified pattern matches more thanone file or directory
# in the archive.
matches="$(ls *"$1" 2>/dev/null | wc -l)"
if [ $matches -eq 0 ] ; then
echo "No match for \"$1\" in the deleted filearchive." >&2
exit 1
fi
if [ $matches -gt 1 ] ; then
echo "More than one file or directory match in the archive:"
index=1
forname in $(ls -td *"$1")
do
datetime="$(echo $name | cut -c1-14| \
awk -F. '{ print $5"/"$4" at"$3":"$2":"$1 }')"
if [ -d $name ] ; then
size="$(ls $name | wc -l | sed 's/[^0-9]//g')"
echo " $index) $1 (contents = ${size} items, deleted =$datetime)"
else
size="$(ls -sdk1 $name | awk '{print $1}')"
echo " $index) $1 (size = ${size}Kb, deleted = $datetime)"
fi
index=$(( $index + 1))
done
echo ""
echo -n "Which version of $1 do you want to restore ('0' to quit)?[1] : "
read desired
if[ ${desired:=1} -ge $index ] ; then
echo "$0: Restore cancelled by user: index value too big.">&2
exit 1
fi
if[ $desired -lt 1 ] ; then
echo "$0: restore cancelled by user." >&2 ; exit 1
fi
restore="$(ls -td1 *"$1" | sed -n"${desired}p")"
if[ -e "$dest/$1" ] ; then
echo "\"$1\" already exists inthis directory. Cannot overwrite." >&2
exit 1
fi
echo -n "Restoring file \"$1\" ..."
$move "$restore" "$dest/$1"
echo "done."
echo -n "Delete the additional copies of this file? [y] "
read answer
if[ ${answer:=y} = "y" ] ; then
$realrm -rf *"$1"
echo "deleted."
else
echo "additional copies retained."
fi
else
if[ -e "$dest/$1" ] ; then
echo "\"$1\" already exists in this directory. Cannotoverwrite." >&2
exit 1
fi
restore="$(ls -d *"$1")"
echo -n "Restoring file \"$1\" ... "
$move "$restore" "$dest/$1"
echo "done."
fi
exit 0
#!/bin/sh
# logrm - log all file deletion requests unless "-s" flag isused
removelog="/tmp/removelog.log"
if [ $# -eq 0 ] ; then
echo "Usage: $0 [-s] list of files or directories" >&2
exit 1
fi
if [ "$1" = "-s" ] ;then
#silent operation requested... don't log
shift
else
echo "$(date): ${USER}: $@" >> $removelog
fi
/bin/rm "$@"
exit 0
#!/bin/sh
# formatdir - output a directory listing ina friendly and useful format
gmk()
{
#given input in Kb, output in Kb, Mb or Gb for best output format
if[ $1 -ge 1000000 ] ; then
echo "$(scriptbc -p 2 $1 / 1000000)Gb"
elif [ $1 -ge 1000 ] ; then
echo "$(scriptbc -p 2 $1 /1000)Mb"
else
echo "${1}Kb"
fi
}
if [ $# -gt 1 ] ; then
echo "Usage: $0 [dirname]" >&2; exit 1
elif [ $# -eq 1 ] ; then
cd"$@"
fi
for file in *
do
if[ -d "$file" ] ; then
size=$(ls "$file" | wc -l | sed 's/[^[:digit:]]//g')
if [ $size -eq 1 ] ; then
echo "$file ($size entry)|"
else
echo "$file ($size entries)|"
fi
else
size="$(ls -sk "$file" | awk '{print $1}')"
echo "$file ($(gmk $size))|"
fi
done | \
sed's/ /^^^/g' | \
xargs -n 2 | \
sed's/\^\^\^/ /g' | \
awk-F\| '{ printf "%-39s %-39s\n", $1, $2 }'
exit 0
#!/bin/sh
# locate - search the locate database forthe specified pattern
locatedb="/var/locate.db"
exec grep -i "$@" $locatedb
#!/bin/sh
# mklocatedb - build the locate databaseusing find. Must be root to run this
locatedb="/var/locate.db"
if [ "$(whoami)" !="root" ] ; then
echo "Must be root to run this command." >&2
exit 1
fi
find / -print > $locatedb
exit 0
#!/bin/sh
# DIR - pretend we're the DIR command in DOS and display the contents
# of the specified file, accepting some of the standard DIR flags
usage()
{
cat << EOF >&2
Usage: $0 [DOS flags] directory or directories
Where:
/D sort by columns
/H show help for this shell script
/N showlong listing format with filenames on right
/OD sort by oldest to newest
/O-D sort by newest tooldest
/P pauseafter each screenful of information
/Q show owner of the file
/S recursive listing
/W usewide listing format
EOF
exit 0
}
postcmd=""
flags=""
while [ $# -gt 0 ]
do
case $1 in
/D ) flags="$flags-x" ;;
/H ) usage ;;
/[NQW]) flags="$flags -l" ;;
/OD ) flags="$flags-rt" ;;
/O-D ) flags="$flags-t" ;;
/P ) postcmd="more" ;;
/S ) flags="$flags-s" ;;
* ) # unknown flag: probably a dir specifier
break; #so let's get outta the while loop
esac
shift # processed flag, let's see if there'sanother
done
# done processing flags, now the commanditself:
if [ ! -z "$postcmd" ] ; then
ls$flags "$@" | $postcmd
else
ls$flags "$@"
fi
exit 0
#!/bin/sh
# findman -- given a pattern and a mansection, show all the matches
# for that pattern from within all relevant man pages.
match1="/tmp/$0.1.$$"
matches="/tmp/$0.$$"
manpagelist=""
trap "rm -f $match1 $matches"EXIT
case $#
in
3 )section="$1" cmdpat="$2" manpagepat="$3" ;;
2 )section="" cmdpat="$1" manpagepat="$2" ;;
* )echo "Usage: $0 [section] cmdpattern manpagepattern" >&2
exit 1
esac
if ! man -k "$cmdpat" | grep"($section" > $match1 ; then
echo "No matches to pattern \"$cmdpat\". Try somethingbroader?"; exit 1
fi
cut -d\( -f1 < $match1 > $matches # command names only
cat /dev/null > $match1 #clear the file...
for manpage in $(cat $matches)
do
manpagelist="$manpagelist $manpage"
man$manpage | col -b | grep -i $manpagepat | \
sed "s/^/${manpage}: /" | tee -a $match1
done
if [ ! -s $match1 ] ; then
cat << EOF
Command pattern "$cmdpat" hadmatches, but within those there were no
matches to your man page pattern"$manpagepat" found in that set.
Man pages checked:$manpagelist
EOF
fi
exit 0
#!/bin/sh
# timein - show the current time in thespecified timezone or
# geographic zone. Without any argument, show UTC/GMT. Use
# the word "list" to see a list of known geographic regions
# Notethat it's possible to match a zone directory (a region)
# but that only timezone files are valid specifications.
# Timezone database ref: http://www.twinsun.com/tz/tz-link.htm
zonedir="/usr/share/zoneinfo"
if [ ! -d $zonedir ] ; then
echo "No timezone database at $zonedir." >&2 ; exit 1
fi
if [ -d "$zonedir/posix" ] ; then
zonedir=$zonedir/posix #modern Linux systems
fi
if [ $# -eq 0 ] ; then
timezone="UTC"
mixedzone="UTC"
elif [ "$1" = "list" ]; then
(echo "All known timezones and regions defined on this system:"
cd $zonedir
find * -type f -print | xargs -n 2 | \
awk '{ printf " %-38s%-38s\n", $1, $2 }'
) |more
exit 0
else
region="$(dirname $1)"
zone="$(basename $1)"
#Is it a direct match? If so, we're good to go. Otherwise we need
#to dig around a bit to find things. Start by just counting matches
matchcnt="$(find $zonedir -name $zone -type f -print |
wc -l | sed 's/[^[:digit:]]//g' )"
if[ "$matchcnt" -gt 0 ] ; then # at least one file matches
if [ $matchcnt -gt 1 ] ; then # more than one file match
echo "\"$zone\" matches more than one possible time zonerecord." >&2
echo "Please use 'list' to see all known regions andtimezones" >&2
exit 1
fi
match="$(find $zonedir -name $zone -type f -print)"
mixedzone="$zone"
else
#Normalize to first upper, rest of word lowercase for region + zone
mixedregion="$(echo ${region%${region#?}} | tr '[[:lower:]]''[[:upper:]]')\
$(echo ${region#?} | tr '[[:upper:]]''[[:lower:]]')"
mixedzone="$(echo ${zone%${zone#?}} | tr '[[:lower:]]''[[:upper:]]')\
$(echo ${zone#?} | tr '[[:upper:]]''[[:lower:]]')"
if [ "$mixedregion" != "." ] ; then
# only look for specified zone in specified region
# to let users specify unique matches when there's more than one
# possibility (e.g., "Atlantic")
match="$(find $zonedir/$mixedregion -type f -name $mixedzone-print)"
else
match="$(find $zonedir -name $mixedzone -type f -print)"
fi
if [ -z "$match" ] ;then # no file matches specified pattern
if [ ! -z $(find $zonedir -name $mixedzone -type d -print) ] ; then
echo \
"The region \"$1\" has more than one timezone. Please use'list'" >&2
else # just not a match at all
echo "Can't find an exact match for \"$1\". Please use'list'" >&2
fi
echo "to see all known regions and timezones." >&2
exit 1
fi
fi
timezone="$match"
fi
nicetz=$(echo $timezone | sed"s|$zonedir/||g") # prettyup the output
echo It\'s $(TZ=$timezone date '+%A, %B %e,%Y, at %l:%M %p') in $nicetz
exit 0
#!/bin/sh
# remember- an easy command-line based memory pad
# search the results with 'remindme'
rememberfile="$HOME/.remember"
if [ $# -eq 0 ] ; then
echo "Enter note, end with ^D: "
cat- >> $rememberfile
else
echo "$@" >> $rememberfile
fi
exit 0
#!/bin/sh
# remindme - search a datafile for matchinglines, or show the contents
# of the datafile if no arg is specified
rememberfile="$HOME/.remember"
if [ $# -eq 0 ] ; then
more $rememberfile
else
grep -i "$@" $rememberfile | ${PAGER:-more}
fi
exit 0
#!/bin/sh
# calc - a command-line calculator thatacts as a front-end to bc
scale=2
show_help()
{
cat << EOF
Inaddition to standard math functions, calc also supports
a %b remainder of a/b
a ^b exponential: a raised to the bpower
s(x) sine of x, x in radians
c(x) cosine of x, x inradians
a(x) arctangent of x,returns radians
l(x) natural log of x
e(x) exponential log ofraising e to the x
j(n,x) bessel function ofinteger order n of x
scaleN show N fractional digits (default =2)
EOF
}
if [ $# -gt 0 ] ; then
exec scriptbc "$@"
fi
echo "Calc - a simple calculator. Use'help' for help, 'quit' to quit."
echo -n "calc> "
while read command args
do
case $command
in
quit|exit) exit 0 ;;
help|\?) show_help ;;
scale) scale=$args ;;
*) scriptbc -p $scale"$command" "$args" ;;
esac
echo -n "calc> "
done
echo ""
exit 0
#!/bin/sh
# checkspelling - check the spelling of aword
spell="ispell -l" # if you have ispell installed instead
# if not, just define spell=spell or
# equivalent.
if [ $# -lt 1 ] ; then
echo "Usage: $0 word or words" >&2
exit 1
fi
for word
do
if[ -z $(echo $word | $spell) ] ; then
echo "$word: spelledcorrectly."
else
echo "$word: misspelled."
fi
done
exit 0