#!/bin/bash # $Id: dir_array,v 1.34 2005/09/02 00:25:19 jlarsen Exp $ # This file has functions for manipulating an array of directories to make # it easy to switch between directories. It handles dirnames with spaces in them. # # Call this file from within your .bashrc so that the functions are loaded when your shell is started. # Make sure it is called after $HISTIGNORE is set in .bashrc because dir_array appends to $HISTIGNORE. # Initialize required variables declare -a DIR_ARRAY DIR_ARRAY[1]=`pwd` ARRAY_TOP=1 ARRAY_IDX=1 PREV_ARRAY_IDX=1 FILE_DIR=~/.dir_array DEFAULT_FILE="default" AUTO_ADD=off # Add all the dir_array function calls to $HISTIGNORE so that they don't fill up the history. # Append to $HISTIGNORE if it exists and create it if it doesn't. For this to work, dir_array must be # called after $HISTIGNORE is set in the user's .bashrc otherwise it will get overwritten. if [ "$HISTIGNORE" != "" ]; then HISTIGNORE="$HISTIGNORE:a .:c:u:j:s:d:s l:s w:s df:s lf:s wf:s a:s af:s ?:b:f:t:j 1:j 2:j 3:j 4:j 5:j 6:j 7:j 8:j 9:j 10:j 11:j 12:j 13:j 14:j 15:j 16:j 17:j 18:j 19" else HISTIGNORE="a .:c:u:j:s:d:s l:s w:s df:s lf:s wf:s a:s af:s ?:b:f:t:j 1:j 2:j 3:j 4:j 5:j 6:j 7:j 8:j 9:j 10:j 11:j 12:j 13:j 14:j 15:j 16:j 17:j 18:j 19" fi # Initialize the version DIR_ARRAY_VER="v`echo '$Id: dir_array,v 1.34 2005/09/02 00:25:19 jlarsen Exp $' | awk '{print $3}'`" DIR_ARRAY_DATE="`echo '$Id: dir_array,v 1.34 2005/09/02 00:25:19 jlarsen Exp $' | awk '{print $4}'`" #----------------------------------------------------------------------------- # dir_array_help - Function that displays help text function dir_array_help () { cat << EOF dir_array command summary: a dir - Append directory to end of list (Accepts ".") b - Backup one directory in list with wrap around c - Clear directory list and put \`pwd\` as entry 1 (See "u" below) d [n] - Delete entry from list. (Accepts "." for current ==> position.) f - Forward one directory in list with wrap around i dir - Insert directory before current directory (Accepts ".") j [n] - Jump to directory in list ("." is a no-op ) (Calls "a" if not in list) s - Show directory list ? - Show this command summary a - Append default file "$DEFAULT_FILE" to directory list af - Append a file from "$FILE_DIR" to directory list df - Delete a file in "$FILE_DIR" l - Load directory list from default file "$DEFAULT_FILE" lf - Load directory list from file in "$FILE_DIR" off - auto_add mode disabled (default startup mode) on - auto_add mode enabled s - Sort the directory list w - Write directory list to default file "$DEFAULT_FILE" wf - Write directory list to file in "$FILE_DIR" t - Toggle back to previous directory u - Undo "c" Note: ==> n points to current directory n < points to previous directory EOF } #----------------------------------------------------------------------------- # a - Function to add a directory to the list # $1 is the directory to add # $2 if not null then the call to "s" is suppressed function a () { # Exit if nothing entered for $1 if [ ! "$1" ]; then echo "Enter valid directory path or \".\"" return fi local entry="$1" # Only do this if the directory exists if [ ! -d "$entry" ]; then echo "Invalid dir: $entry" return fi # Expand "." to full path name if [ "$entry" = "." ]; then entry=`pwd` fi # If directory is relative pathname then cd first to get full pathname from pwd if [ "${entry:0:1}" != "/" ]; then builtin cd "$entry" entry=`pwd` fi # Strip off a trailing "/". Solaris puts them in there when using file completion. entry=`echo "$entry" | sed -e 's/\/$//'` # If entry is now null then directory was root "/" so put the slash back in if [ ${#entry} -eq 0 ]; then entry="/" fi # Only add this to the array if it isn't already in the array. Otherwise, cd to it. local index=1 while [ $index -le $ARRAY_TOP ]; do if [ "$entry" = "${DIR_ARRAY[$index]}" ]; then builtin cd "${DIR_ARRAY[$index]}" ARRAY_IDX=$index if [ "$2" == "" ]; then s fi return fi let index=index+1 done # Directory exists and isn't in the array so add it and cd to the array let ARRAY_TOP=ARRAY_TOP+1 DIR_ARRAY[$ARRAY_TOP]="$entry" PREV_ARRAY_IDX=$ARRAY_IDX ARRAY_IDX=$ARRAY_TOP builtin cd "$entry" if [ "$2" == "" ]; then s fi } # a #----------------------------------------------------------------------------- # b - Function to move backward one position in the array function b () { PREV_ARRAY_IDX=$ARRAY_IDX let ARRAY_IDX=ARRAY_IDX-1 if [ $ARRAY_IDX -le 0 ]; then ARRAY_IDX=$ARRAY_TOP fi builtin cd "${DIR_ARRAY[$ARRAY_IDX]}" #s } # b #----------------------------------------------------------------------------- # c - Function that clears the entire array function c () { OLD_ARRAY_TOP=$ARRAY_TOP ARRAY_TOP=1 OLD_PREV_ARRAY_IDX=$PREV_ARRAY_IDX PREV_ARRAY_IDX=1 OLD_ARRAY_IDX=$ARRAY_IDX ARRAY_IDX=1 OLD_DIR_ARRAY_1=${DIR_ARRAY[1]} DIR_ARRAY[1]=`pwd` s } # c #----------------------------------------------------------------------------- # cd - Function used to auto add directories when autoadd is enabled function cd () { if [ "$AUTO_ADD" == "off" ]; then if [[ "$1" == "" ]]; then builtin cd ~ else builtin cd "$*" fi else if [[ "$1" == "" ]]; then a ~ no_show else a "$1" no_show fi fi } # cd #----------------------------------------------------------------------------- # d - Function to delete a directory from the array function d () { # Don't delete the only entry left if [ $ARRAY_TOP -le 1 ]; then return; fi # Display list if number not on the command line. Accept "." as current directory entry. if [ $1 ]; then if [ "$1" = "." ]; then local entry=$ARRAY_IDX else if [ $1 -lt 1 -o $1 -gt $ARRAY_TOP ]; then echo "Error: Number out of range" return fi local entry=$1 fi else s local response="" while [ "$response" = "" ]; do read -a response -p "Delete entry (CR to exit): " # Exit if no number was entered if [ "$response" = "" ]; then return fi # Use current pointer value if "." entered if [ "$response" = "." ]; then local entry=$ARRAY_IDX else if [ $response -lt 1 -o $response -gt $ARRAY_TOP ]; then echo "Error: Number out of range" return fi local entry=$response fi done fi # Setup to shift array contents down local index1="$entry" local index2="$entry" let index2=index2+1 # Adjust ARRAY_IDX down one if its value is higher or equal to the entry to be deleted if [ $ARRAY_IDX -ge $index1 ]; then let ARRAY_IDX=ARRAY_IDX-1 if [ $ARRAY_IDX -le 0 ]; then ARRAY_IDX=1 fi fi # Adjust PREV_ARRAY_IDX down one if its value is higher or equal to the entry to be deleted if [ $PREV_ARRAY_IDX -ge $index1 ]; then let PREV_ARRAY_IDX=PREV_ARRAY_IDX-1 if [ $PREV_ARRAY_IDX -le 0 ]; then PREV_ARRAY_IDX=1 fi fi # Make the move while [ $index2 -le $ARRAY_TOP ]; do DIR_ARRAY[$index1]=${DIR_ARRAY[$index2]} let index1=index1+1 let index2=index2+1 done # Adjust the top of the array down let ARRAY_TOP=ARRAY_TOP-1 # cd to the array entry pointed to by ARRAY_IDX in case it changed builtin cd "${DIR_ARRAY[$ARRAY_IDX]}" s } # d #----------------------------------------------------------------------------- # f - Function to move forward one position in the array function f () { PREV_ARRAY_IDX=$ARRAY_IDX let ARRAY_IDX=ARRAY_IDX+1 if [ $ARRAY_IDX -gt $ARRAY_TOP ]; then ARRAY_IDX=1 fi builtin cd "${DIR_ARRAY[$ARRAY_IDX]}" #s } # f #----------------------------------------------------------------------------- # i - Function to inserts a directory at the current location in the array function i () { # Exit if nothing entered for $1 if [ ! "$1" ]; then echo "Enter valid directory path or \".\"" return fi local entry="$1" # Only do this if the directory exists if [ ! -d "$entry" ]; then echo "Invalid dir: $entry" return fi # Expand "." to full path name if [ "$entry" = "." ]; then entry=`pwd` fi # If directory is relative pathname then cd first to get full pathname from pwd if [ "${entry:0:1}" != "/" ]; then builtin cd "$entry" entry=`pwd` fi # Strip off a trailing "/". Solaris puts them in there when using file completion. entry=`echo "$entry" | sed -e 's/\/$//'` # If entry is now null then directory was root "/" so put the slash back in if [ ${#entry} -eq 0 ]; then entry="/" fi # Only add this to the array if it isn't already in the array local index=1 while [ $index -le $ARRAY_TOP ]; do if [ "$entry" = "${DIR_ARRAY[$index]}" ]; then builtin cd "${DIR_ARRAY[$index]}" ARRAY_IDX=$index s return fi let index=index+1 done # Directory exists and isn't in the array so add it and CD to the array # First move all array entries up one to open a spot for new directory local index1=$ARRAY_TOP let ARRAY_TOP=ARRAY_TOP+1 local index2=$ARRAY_TOP while [ $index1 -ge $ARRAY_IDX ]; do DIR_ARRAY[$index2]=${DIR_ARRAY[$index1]} let index1=index1-1 let index2=index2-1 done # Save previous ARRAY_IDX for use by "t" let PREV_ARRAY_IDX=ARRAY_IDX+1 # Now put the new directory in the array DIR_ARRAY[$ARRAY_IDX]="$entry" builtin cd "$entry" s } # i #----------------------------------------------------------------------------- # j - Function to jump to a directory function j () { if [ $1 ]; then # Handle the "." case by calling "a" with current directory if [ "$1" = "." ]; then a `pwd` return fi # Look for alpha characters and call "a" if found local num_test=`echo $1 | sed -e 's/^[1-9].*/NUM/p'` if [ "${num_test:0:3}" != "NUM" ]; then a "$1" return fi # Number entered so try using it if [ $1 -lt 1 -o $1 -gt $ARRAY_TOP ]; then s echo "Error: Number out of range" return fi # Only need to update and jump if $1 isn't the same as ARRAY_IDX if [ $1 -ne $ARRAY_IDX ]; then PREV_ARRAY_IDX=$ARRAY_IDX let ARRAY_IDX=$1 builtin cd "${DIR_ARRAY[$ARRAY_IDX]}" else # If pwd doesn't equal DIR_ARRAY[$ARRAY_IDX] then need to jump back if [ "`pwd`" != "${DIR_ARRAY[$ARRAY_IDX]}" ]; then builtin cd "${DIR_ARRAY[$ARRAY_IDX]}" fi fi #s else # Nothing entered in $1 so show the list and ask where to jump s local response="" while [ "$response" = "" ]; do read -a response -p "Select directory: " if [ "$response" = "." -o "$response" = "" ]; then return else if [ $response -lt 1 -o $response -gt $ARRAY_TOP ]; then echo "Error: Number out of range" return fi fi done # Only need to update and jump if $response isn't the same as ARRAY_IDX if [ $response -ne $ARRAY_IDX ]; then PREV_ARRAY_IDX=$ARRAY_IDX ARRAY_IDX=$response builtin cd "${DIR_ARRAY[$ARRAY_IDX]}" else # If pwd doesn't equal DIR_ARRAY[$ARRAY_IDX] then need to jump back if [ "`pwd`" != "${DIR_ARRAY[$ARRAY_IDX]}" ]; then builtin cd "${DIR_ARRAY[$ARRAY_IDX]}" fi fi #s fi } # j #----------------------------------------------------------------------------- # s - Function to show contents of the directory array or help if $1 isn't null function s () { if [ $1 ]; then case $1 in a) # Append default $DEFAULT_FILE file to $DIR_ARRAY append_dir_array $FILE_DIR/$DEFAULT_FILE return ;; af) # Append file from $FILE_DIR to $DIR_ARRAY append_dir_array_file return ;; df) # Delete file from $FILE_DIR delete_dir_array_file return ;; l) # Load $DIR_ARRAY from default file $DEFAULT_FILE load_dir_array $FILE_DIR/$DEFAULT_FILE return ;; lf) # Load $DIR_ARRAY from file in $FILE_DIR load_dir_array_file return ;; off) # Disable auto add mode AUTO_ADD=off echo "auto_add mode \"off\"" return ;; on) # Enable auto add mode AUTO_ADD=on echo "auto_add mode \"on\"" return ;; s) # Sort directory list sort_dir_array return ;; w) # Write DIR_ARRAY to default file $DEFAULT_FILE write_dir_array $FILE_DIR/$DEFAULT_FILE return ;; wf) # Write DIR_ARRAY to file in $FILE_DIR write_dir_array_file return ;; *) # Display command line reference dir_array_help ;; esac else local index=1 local current_dir=`pwd` while [ $index -le $ARRAY_TOP ]; do if [ $index -eq $ARRAY_IDX -a "$current_dir" = "${DIR_ARRAY[$index]}" ]; then if [ $index -eq $PREV_ARRAY_IDX ]; then if [ $index -lt 10 ]; then printf "==> %d.< %s\n" $index "${DIR_ARRAY[$index]}" else printf "==>%d.< %s\n" $index "${DIR_ARRAY[$index]}" fi else if [ $index -lt 10 ]; then printf "==> %d. %s\n" $index "${DIR_ARRAY[$index]}" else printf "==>%d. %s\n" $index "${DIR_ARRAY[$index]}" fi fi else if [ $index -eq $PREV_ARRAY_IDX ]; then if [ $index -lt 10 ]; then printf " %d.< %s\n" $index "${DIR_ARRAY[$index]}" else printf " %d.< %s\n" $index "${DIR_ARRAY[$index]}" fi else if [ $index -lt 10 ]; then printf " %d. %s\n" $index "${DIR_ARRAY[$index]}" else printf " %d. %s\n" $index "${DIR_ARRAY[$index]}" fi fi fi let index=index+1 done fi echo "-----------------(auto_add: $AUTO_ADD)--( help: s ? )-- dir_array $DIR_ARRAY_VER $DIR_ARRAY_DATE ----" } # s #----------------------------------------------------------------------------- # t - Function to toggle back to previously selected directory function t () { if [ "${DIR_ARRAY[$ARRAY_IDX]}" != "`pwd`" ]; then a "`pwd`" no_show fi local temp=$ARRAY_IDX ARRAY_IDX=$PREV_ARRAY_IDX PREV_ARRAY_IDX=$temp builtin cd "${DIR_ARRAY[$ARRAY_IDX]}" #s } # t #----------------------------------------------------------------------------- # u - Function that undoes the "c" command function u () { ARRAY_TOP=$OLD_ARRAY_TOP ARRAY_IDX=$OLD_ARRAY_IDX PREV_ARRAY_IDX=$OLD_PREV_ARRAY_IDX DIR_ARRAY[1]=$OLD_DIR_ARRAY_1 builtin cd "${DIR_ARRAY[$ARRAY_IDX]}" s } # u #----------------------------------------------------------------------------- # sort_dir_array - Function that sorts the array in alphabetical order function sort_dir_array () { # Only do this if array has more than one entry if [ $ARRAY_TOP -eq 1 ]; then return fi # Sort the list local change=YES while [ "$change" == "YES" ]; do local index1=1 local index2=2 change=NO while [ $index2 -le $ARRAY_TOP ]; do if [[ "${DIR_ARRAY[$index1]}" > "${DIR_ARRAY[$index2]}" ]]; then change=YES local temp=${DIR_ARRAY[$index1]} DIR_ARRAY[$index1]=${DIR_ARRAY[$index2]} DIR_ARRAY[$index2]=$temp # Make sure the ARRAY_IDX follows the sorting if [ $ARRAY_IDX -eq $index2 ]; then ARRAY_IDX=$index1 else if [ $ARRAY_IDX -eq $index1 ]; then ARRAY_IDX=$index2 fi fi # Make sure the PREV_ARRAY_IDX follows the sorting if [ $PREV_ARRAY_IDX -eq $index2 ]; then PREV_ARRAY_IDX=$index1 else if [ $PREV_ARRAY_IDX -eq $index1 ]; then PREV_ARRAY_IDX=$index2 fi fi fi let index1=index1+1 let index2=index2+1 done done s } # sort_dir_array #----------------------------------------------------------------------------- # write_dir_array - Function that writes the DIR_ARRAY to a file $1 # $1 is name of file to write function write_dir_array () { # Create the directory if it doesn't exist if [ ! -d $FILE_DIR ]; then mkdir $FILE_DIR fi # Remove the file if it already exists if [ -e "$1" ]; then rm -f "$1" fi # Write to the file local index=1 while [ $index -le $ARRAY_TOP ]; do echo ${DIR_ARRAY[$index]} >> "$1" let index=index+1 done } # write_dir_array #----------------------------------------------------------------------------- # append_dir_array - Function that appends the file passed in $1 to DIR_ARRAY # $1 is the file to append function append_dir_array () { if [ -e "$1" ]; then local lines=`wc -l < "$1"` local line_cnt=1 while [ $line_cnt -le $lines ]; do # Create a sed script to isolate one line from the file then read it in # 040605 jrl - This sed method required to handle dirnames with spaces in them echo "${line_cnt}p" >| /tmp/$$.sed #DIR_ARRAY[$line_cnt]=`sed -n -f /tmp/$$.sed < "$1"` local entry=`sed -n -f /tmp/$$.sed < "$1"` rm -f /tmp/$$.sed # Check if entry is already in the current DIR_ARRAY local index=1 local found=FALSE while [ $index -le $ARRAY_TOP ]; do if [ "$entry" = "${DIR_ARRAY[$index]}" ]; then found=TRUE fi let index=index+1 done # Add the entry to the top of DIR_ARRAY if it isn't already in it if [ $found = FALSE ]; then let ARRAY_TOP=ARRAY_TOP+1 DIR_ARRAY[$ARRAY_TOP]="$entry" fi # Point to the next line in the file let line_cnt=line_cnt+1 done s fi } # append_dir_array #----------------------------------------------------------------------------- # load_dir_array - Function that loads the DIR_ARRAY from a file # $1 is the file to load function load_dir_array () { if [ -e "$1" ]; then local lines=`wc -l < "$1"` local line_cnt=1 while [ $line_cnt -le $lines ]; do # Create a sed script to isolate one line from the file then read it in # 040605 jrl - This sed method required to handle dirnames with spaces in them echo "${line_cnt}p" >| /tmp/$$.sed DIR_ARRAY[$line_cnt]=`sed -n -f /tmp/$$.sed < "$1"` rm -f /tmp/$$.sed # Point to the next line in the file let line_cnt=line_cnt+1 done # Initialize the ARRAY_TOP to be the number of lines in $1 ARRAY_TOP=$lines i `pwd` fi } # load_dir_array #----------------------------------------------------------------------------- # load_dir_array_file - Function that loads the DIR_ARRAY from a file in $FILE_DIR function load_dir_array_file () { if [ -d $FILE_DIR ]; then contents=`ls $FILE_DIR` PS3="Choose file (. to exit): " select file_name in $contents; do if [ "$REPLY" = "." ]; then return fi if [ "$file_name" != "" ]; then load_dir_array $FILE_DIR/$file_name return fi done else echo "Directory $FILE_DIR does not exist" fi } # load_dir_array_file #----------------------------------------------------------------------------- # append_dir_array_file - Function that appends the DIR_ARRAY from a file in $FILE_DIR function append_dir_array_file () { if [ -d $FILE_DIR ]; then contents=`ls $FILE_DIR` PS3="Choose file (. to exit): " select file_name in $contents; do if [ "$REPLY" = "." ]; then return fi if [ "$file_name" != "" ]; then append_dir_array $FILE_DIR/$file_name return fi done else echo "Directory $FILE_DIR does not exist" fi } # append_dir_array_file #----------------------------------------------------------------------------- # write_dir_array_file - Function that writes the DIR_ARRAY to a file in $FILE_DIR function write_dir_array_file () { if [ -d $FILE_DIR ]; then contents=`ls $FILE_DIR` PS3="Choose file or enter new name (. to exit): " select file_name in $contents; do if [ "$REPLY" = "." ]; then return fi if [ "$file_name" != "" ]; then write_dir_array $FILE_DIR/$file_name return fi if [ "$file_name" = "" -a "$REPLY" != "" ]; then write_dir_array $FILE_DIR/$REPLY return fi done else echo "Directory $FILE_DIR does not exist" fi } # write_dir_array_file #----------------------------------------------------------------------------- # delete_dir_array_file - Function that deletes a file from $FILE_DIR function delete_dir_array_file () { if [ -d $FILE_DIR ]; then contents=`ls $FILE_DIR` PS3="Choose file to delete (. to exit): " select file_name in $contents; do if [ "$REPLY" = "." ]; then return fi # Don't allow $DEFAULT_FILE to be removed if [ "$file_name" = "$DEFAULT_FILE" ]; then echo "Can't remove \"$DEFAULT_FILE\"" return fi # Remove the file if $file_name isn't null if [ "$file_name" != "" ]; then rm -f $FILE_DIR/$file_name return fi done else echo "Directory $FILE_DIR does not exist" fi } # delete_dir_array_file