#!/bin/bash ########################################################################### # # rove Version 0.4 # # Designed to allow you to recurse over a selected set of directories and # execute any given command from that directory. Please note that complex # commands require extensive knowledge of shell metacharacter escapement. # # Written by Jeff Albro , with pointers from Patrick # Jordan . # # Copyright 2002, Jeff Albro, Liscensed under the GNU GPL, Version 2. # # See www.gnu.org for details. # # Compatability: # # May need minor tweaks to run under ksh. Should run fine under sh if # getopts exists. Getopt can be used instead, but it is less robust. # # To do: # # Allow for preexecution queries # Add provsion for dealing with hidden directories. # ########################################################################### ##################################### # some global information version="0.4" ############################################ # function to clue the user in, then exit... echo_usage () { cat < Usage: rove [-ce#fils#tvw] start-directory [command] Options: -c check command before executing (recommended) -e# end level (level 0 is the start directory) -f follow symbolic links -i interactive (implies -c) -l leaves only (execute in directories without subdirectories) -s# start level (level 0 is the start directory) -t top down (default is bottom up) -v verbose -w wood only (execute in directories with subdirectories) Warning: Be sure to escape metacharacters such as $<>&|(); with a \ or by quoting to bypass intial shell evaluation, if desired. Use -c for pre-confirmation. EOF exit $1 } ################################################ # determine if a directory has no subdirectories leaf () { if [ -z "$(command find $1 -mindepth 1 -maxdepth 1 -type d)" ]; then return 0 else return 1 fi } ########################################################## # determine if a directory has at least one subdirectories wood () { if [ -n "$(command find $1 -mindepth 1 -maxdepth 1 -type d )" ]; then return 0 else return 1 fi } #################### # begin main program opt_command="" opt_end="" opt_end_level="" opt_followlinks="" opt_interactive="" opt_leaves="" opt_start="" opt_start_level="" opt_top_down="-depth" opt_verbose="" opt_wood="" ################################ # need to save starting location start=$PWD ################# # process options while getopts ":ce:fils:tvw" opt do case $opt in c) opt_command="TRUE";; e) opt_end="-maxdepth"; opt_end_level="$OPTARG";; f) opt_followlinks="-follow";; i) opt_interactive="TRUE"; opt_command="TRUE";; l) opt_leaves="TRUE";; s) opt_start="-mindepth"; opt_start_level="$OPTARG";; t) opt_top_down="";; v) opt_verbose="TRUE";; w) opt_wood="TRUE";; ?) echo_usage 1;; esac done shift $(($OPTIND - 1)) ################################# # time out for error checking if [ $# = 0 ]; then echo_usage 1 fi if [ -n "$opt_wood" ] && [ -n "$opt_leaves" ]; then echo_usage 1 fi ################################# # continue preprocessing findstart=$1 shift command=$@ ############################# # print the command if [ -n "$opt_verbose" ] || [ -n "$opt_command" ]; then if [ -n "$command" ]; then echo echo "\"$command\" will be executed in each processed directory" echo else echo echo "No commands to be executed" echo fi fi if [ -n "$opt_command" ]; then #query user while [ true ]; do echo -n "Is this what you want? (Y/n) " read answer if [ "$answer" = "n" ] || [ "$answer" = "N" ]; then echo echo "exiting..." echo exit 1 elif [ "$answer" = "Y" ] || [ "answer" = "y" ] || [ -z "$answer" ]; then echo echo "continuing..." echo break else echo echo "Invalid answer, please try again..." echo fi done fi ################################## # get unfiltered directory listing preliminary_list=$(command find $findstart $opt_followlinks $opt_start $opt_start_level $opt_end $opt_end_level $opt_top_down -type d) ############################## # filter preliminary_list here if [ -n "$opt_leaves" ]; then for directory in $preliminary_list; do if leaf $directory; then directory_list="$directory_list $directory" fi done elif [ -n "$opt_wood" ]; then for directory in $preliminary_list; do if wood $directory; then directory_list="$directory_list $directory" fi done else directory_list=$preliminary_list fi ##################### # process directories for directory in $directory_list; do if [ -n "$opt_interactive" ]; then #query user while [ true ]; do echo -n "Process $directory? (Y/n/q) " read answer if [ "$answer" = "y" ] || [ "$answer" = "Y" ] || [ -z "$answer" ]; then command cd $directory eval $command command cd $start break elif [ "$answer" = "n" ] || [ "$answer" = "N" ]; then break elif [ "$answer" = "q" ] || [ "$answer" = "Q" ]; then echo echo "exiting..." echo exit 1 else echo echo "Invalid answer, please try again..." echo fi done elif [ -n "$opt_verbose" ]; then echo "Processing $directory" command cd $directory eval $command command cd $start else command cd $directory eval $command command cd $start fi done ################## #exit successfully exit 0 ################## # end of rove