Advertisement
robertmarkbram

Bash script to search for and open files

Jan 17th, 2015
493
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 32.19 KB | None | 0 0
  1. #!/bin/bash
  2.  
  3. # ------------------------------------------------------------------------------
  4. # -- Editor's Little Helper. :)
  5. # ------------------------------------------------------------------------------
  6. # Open and/or search for a set of files and open them in your favourite text
  7. # editor.
  8. #
  9. # Author: Robert Mark Bram
  10. # v 1.2 - 21/06/2007 1:03PM. Made the script interactive
  11. # v 1.3 - 26/06/2007 7:46AM. Modified usage comments. Fixed handling of spaces
  12. #   in files names.
  13. # v 1.4 - 6/07/2007 3:16:51 PM. Modified to protect against invalid indexes
  14. #   being entered by the user.
  15. # v 1.5 - 8/07/2007 4:31:23 PM. Split openFile function into open file by index
  16. #   or path where each method should be called explicitly. Fixed error where
  17. #   script was opening all by index, assuming paths were indexes!
  18. # v 1.6 - 8/07/2007 4:37:47 PM. Split printListOfFiles function into two
  19. #   functions, one that would print the index of each file along with the file
  20. #   path, and one that would only print the path. Useful if this command is to
  21. #   be part of a pipe.
  22. # v 1.7 - 19/11/2007 12:31:44 PM. Included the ability to follow (or not) symbolic
  23. #   links by hooking into the find command's capability for this. By default, do
  24. #   not follow symbolic links.
  25. # v 1.8 - 29/02/2008 3:23:20 PM. Exclude files matching:
  26. #   grep -v '[.]svn-base$\|zzbuild\|[.]class$\|[.]bak$'
  27. # v 1.8.1 - 12/05/2008 5:16:51 PM. Added another path for ultra edit.
  28. # Thursday 6 June 2013, 04:17:59 PM
  29. # - Fixed second method of opening files in Eclipse.
  30. # Friday 31 January 2014, 05:22:54 PM
  31. # - Minor format change to the way I declare functions.
  32. # Friday 28 February 2014, 06:31:37 PM
  33. # - Major update that took all day when I should have been working.. but oh well:
  34. #    It was worth it. :)
  35. # - Modified handling of files so that a single file or whole array can be opened
  36. #    in the editor in one step.
  37. # - Cleaned up usage function.
  38. # - Modify argument handling to use processArguments function with getopts.
  39. # - Update script so that you give choice of editors: vim, ultraedit, eclipse,
  40. #    notepad; no more can you specify editor command by name - you must choose
  41. #    one of these. Otherwise, it is too hard to know how to handle the "x"
  42. #    choice - you don't know if it is a Windows or Cygwin exe so you don't know
  43. #    for sure whether you should process the paths.
  44. # - Let user change editor from document selection screen.
  45. # - Add verbose option through the message function, which checks if verbose is
  46. #    on or not.
  47. # - Double check if examples are OK and still relevant.
  48. # - Check all exit values to make non-0 cases unique.
  49. # - Added function comments.
  50. # Monday 3 March 2014, 03:22:44 PM
  51. # - Change -L option for following symbolic links to -y instead.
  52. # - Removed -P option for not following symbolic links and left it as the
  53. #     default option, which can be toggled by -y.
  54. # - Added -L searchTerm option so that if using less or vim, open files
  55. #     searching for searchTerm.
  56. # Tuesday 4 March 2014, 06:46:25 PM
  57. # - Changed usage to output $commandName.
  58. # - Changed the way we deal with case sensitivity from command line options so that it can be applied more regularly across find and grep commands.
  59. # - Changed the way we deal with regex from command line options so that we can change find commands properly.
  60. # - Removed fileNamePattern and am just using filePattern.
  61. # - Keep arguments to find and grep in separate arrays: findArg grepArg.
  62. # - Big update to commnts to reflect a separation of argument types: -f, -F and -y to modify the find command; other trailing arguments to modify the grep.
  63. # - Process all arguments to script in same function. How to handle getopts args and operands at the same time: http://stackoverflow.com/a/21169366/257233
  64. # - Added -y option as per search.
  65. # - Added verbose handling and outputAllArgs()
  66. # - Simplified use of find command in getFilesFromFind() to use an array of args.
  67. # Tuesday 4 March 2014, 06:56:10 PM
  68. # - Updated usage comments.
  69. # Thursday 6 March 2014, 12:29:58 PM
  70. # - Modified handling of startOfSubjectLine option because it wasn't working. Gawk sees ^ as start of the whole record string, not as start of a new line, and gawk doesn't have \n at the start of each record.. so I have to be a bit more creative and recognise that a record set starts with a line that ends with >>.
  71. # - Re-added -F option when using less so that if output is less than one screen, it doesn't take over whole screen.
  72. # - Updated these comments.
  73. # Wednesday 05 November 2014, 12:04:39 PM
  74. # - Deal with file/folder names containing space by changing IFS.
  75. # Monday 05 January 2015, 06:19:22 PM
  76. # - Added "/target/" to the exclusion string.
  77. # Sunday 18 January 2015, 02:13:34 PM
  78. # - Update doc for dependencies.
  79.  
  80. # ------------------------------------------------------------------------------
  81. # -- Dependencies
  82. # ------------------------------------------------------------------------------
  83. # Path to UltraEdit to be set in environment variable UEDIT.
  84. # Path to Eclipse to be set in environment variable ECLIPSE.
  85.  
  86. # ------------------------------------------------------------------------------
  87. # -- Variables for this script.
  88. # ------------------------------------------------------------------------------
  89. # Shortcut for the name of this file - for docs.
  90. commandName=`echo $0 | sed 's|.*/||'`
  91. # Directory from which we search for files.
  92. baseDir=.
  93. # Case insensitive by default - used for FindArg and GrepArg
  94. caseSensitive=no
  95. # Follow symbolic links? As per the find command. Defaults to no (-P). Used for FindArg
  96. symbolic=-P
  97. # Will the find command be regex or not - used for FindArg
  98. findArgRegex=no
  99. # Pattern to use in find command - specificed by FindArg.
  100. filePattern=*
  101. # Form used for find command
  102. findArg=()
  103. # Form used for grep command
  104. grepArg=()
  105. # Absolute path (or command string) to the editor to use when opening up files.
  106. editor=u
  107. # Interactive mode: [F]ull, [L]ist, [N]one or [P]artial.
  108. interactivityMode=P
  109. # If in partial interactivity, how many files do we have to find in order to
  110. # trigger interactivity?
  111. minFilesInteractive=2
  112. # Did we actually have to search for files? If no, then all trailing args to
  113. # this script were valid relative paths from base dir or valid absolute paths.
  114. # Needed to work out what to do in partial interactivity mode.
  115. searchPerformed=N
  116. # Array of files given from the command line
  117. arrayOfFilesFromCommandLine=()
  118. # Message to display when need to output editor choice in an echo.
  119. editorChoiceMessage='EDITOR can be one of [e]clipse, [u]ltraedit, [l]ess, n[o]tepad or [v]im.'
  120. # Should we be verbose?
  121. verbose=no
  122. # If using the -L option, store search term here.
  123. searchTermLess=
  124. # Files to exclude in search in FIND command.
  125. excludeParams=(-not -iwholename '*.svn*' -not -iwholename '*.bak*' -not -iwholename '*.class*' -not -ipath '*/target/*')
  126.  
  127. # ------------------------------------------------------------------------------
  128. # -- Common functions for this script.
  129. # ------------------------------------------------------------------------------
  130.  
  131. # ===  FUNCTION  ===============================================================
  132. #   DESCRIPTION:  Output message if verbose is on
  133. #    PARAMETERS:  message to be printed
  134. #       RETURNS:  -
  135. # ==============================================================================
  136. function message() {
  137.    if [ "$verbose" == "yes" ] ; then
  138.       echo -e "${1}"
  139.    fi
  140. }
  141.  
  142. # ===  FUNCTION  ===============================================================
  143. #   DESCRIPTION:  Output help and usage message
  144. #    PARAMETERS:  error message to be printed
  145. #       RETURNS:  -
  146. # ==============================================================================
  147. function usage() {
  148. errMessage=
  149. if [ "$#" -gt 0 ] ; then
  150.    errMessage=$1
  151. else
  152.    errMessage=HELP
  153. fi
  154. less << STOP_HELP
  155. $errMessage
  156. Search for a set of files and open them in your favourite text editor
  157.    Usage: $commandName [Miscellaneous Arguments] [FindArg] [GrepArg ... ]
  158. Works in three parts
  159.    - FindArg is used in a find command to create the superset of files.
  160.    - GrepArg is used to filter the superset to make a subset - one for each
  161.       GrepArg supplied
  162.    - GrepArg (trailing args) could also be actual paths to existing files,
  163.       in which case no grepping is actually needed.
  164.  
  165. --- FindArg
  166. Used to form find command to construct superset of files.
  167. Must use one of the below forms to specify file type for the search.
  168.          -f filePattern   Search pattern for file names. Argument is as per
  169.                           "find . -name FILE_NAME_PATTERN". Not regex.
  170.          -F filePattern   Search pattern for file names. Argument is as per
  171.                           "find . -regex FILE_NAME_PATTERN". IS A REGEX.
  172.                 -y type   File pattern based on file extension using a type
  173.                           shortcut from below.
  174. Available type shortcuts:
  175.                       a   *.js files - Javascript.
  176.                       b   *.php files.
  177.                       c   *.css files.
  178.                       d   *.sh files.
  179.                       e   Everything except things defined here:
  180.                               ${excludeParams[@]}
  181.                       E   Everything including bak and svn and class
  182.                       h   *.html or *.htm files.
  183.                       i   *.idx files.
  184.                       j   *.java files.
  185.                       j   *.sh files - shell files.
  186.                       p   *.jsp|jsph files.
  187.                       r   *.properties files.
  188.                       s   *.sql files.
  189.                       t   *.txt files.
  190.                       x   *.xml files.
  191.                       z   All Java related files
  192.                            *.java files.
  193.                            *.jsp|jsph files.
  194.                            *.properties files.
  195. --- GrepArg
  196. A series of optional regular expressions.
  197.  
  198. --- Miscellaneous Arguments
  199.          [-d directory] Use directory other than default - which is the current dir.
  200.             [-e editor] Specify an editor to use.
  201.                         $editorChoiceMessage
  202.              [-h|-help] Displays this message and exits.
  203.             [-i option] Define mode of interactivity. Defaults to Partial.
  204.                         [F]ull: display lists of files and ask user what ones to open.
  205.                         [L]ist: lists files only. No other form of interaction.
  206.                         [N]one: do not display list of files or ask the user anything:
  207.                            automatically open all files found.
  208.                         [P]artial: can act as Full or None as per below.
  209.                            - act as None if number of files found <= MIN_FILES_INTERACTIVE
  210.                            - act as None if all trailing args were valid relative
  211.                               paths to files from DIRECTORY or valid absolute paths.
  212.         [-L searchTerm] If using -e l|v, this option will ensure that when the file is
  213.                         opened in less or vim, searchTerm will be searched for.
  214. [-m min_files_interactive]
  215.                         Set the minimum number of files that should be found in order
  216.                         to trigger interaction when in Partial interactivity mode.
  217.                         Defaults to 2.
  218.                    [-s] Case sensitive.
  219.                    [-v] Verbose output.
  220.                    [-y] Follow symbolic links (as per find command).
  221.                         Default is never follow  symbolic  links.
  222.  
  223. ==========================
  224. General process for searching for files.
  225.  
  226. 1) Find superset of files from target directory with the find command.
  227.     - Can apply arguments to modify find command file name pattern.
  228.     - Can apply arguments to modify target directory.
  229. 2) Apply regular expressions to superset of files to get selection set.
  230.     - Can use one or more regular expressions via trailing arguments
  231.       to this command.
  232.     - By default, ignores a common set of files through this snippet sent to find:
  233.          ${excludeParams[@]}
  234. 3) Ask what files you wish to open in the editor.
  235.     - Can apply argument to turn off interactive mode - all files get
  236.       opened.
  237.     - Can apply argument to set your own editor.
  238.  
  239. ==========================
  240. Examples.
  241.  
  242. $0 -i l "commandbean.java$"
  243.    List all files from the current directory down whose relative path
  244.    (including file name) ends with "commandbean.java" - case
  245.    insensitive. Here it is effectievly doing:
  246.    find . -name "*" | grep -i "commandbean.java$"
  247.  
  248. $0 -i l -f "*.java" commandbean
  249. $0 -i l -f ".*commandbean.*\\.java"
  250. $0 -i l -f ".*commandbean.*.java"
  251.    List all files from the current directory down whose file name
  252.    ends with ".java" and whose relative path - including file name -
  253.    contains "commandbean" - case insensitive. Here it is effectievly
  254.    doing:
  255.    find . -name "*.java" | grep -i "commandbean"
  256.  
  257. $0 "status.*/.*java$"
  258. $0  -f "*.java" "status.*/"
  259.    Ask me to open files from list of Java source files in a package
  260.    that includes the token "status" somewhere in it -- assuming there
  261.    are more than 1.
  262.  
  263. $0 ./some/path/to/MyClass1.java \\
  264. ./some/path/to/MyClass2.java \\
  265. ./some/path/to/MyClass3.java \\
  266.    Open up the files specified in UltraEdit.
  267.  
  268. $0 ./some/path/to/MyClass1.java ".*.properties$"
  269.    Ask me to open files from list of a specific Java source file and
  270.    all properties file that are found in /base/dir -- assuming the
  271.    list has more than 1 result.
  272.  
  273. $0 ./some/path/to/MyClass1.java -e v -L "This is a comment"
  274.    Open MyClass1.java in vim and automatically search for the string "This is a
  275.   comment"
  276.  
  277. Things that should show the same results:
  278. - Testing find args for files in ./libs/ctags58/*. Note: -regex in find covers file path and name.
  279.       cd ~ ; find . -type f -regex ".*libs.*ctags58.*"
  280.       cd ~ ; find . -type f -regex ".*libs.*ctags58.*" | wc -l
  281.       u -i l -F ".*libs.*ctags58.*" -s
  282.       u -i l -F ".*libs.*ctAGS58.*"
  283. - Testing find args for files va*.vim. Note: -name in find covers file name only.
  284.       cd ~ ; find . -type f -name "va*.vim"
  285.       u -i l -d ~ -f "va*.vim" -s
  286.       u -i l -d ~ -f "VA*.Vim"
  287. - Testing find args using type
  288.    cd ~/nd ; find . -type f -name "*.html" -o -name "*.htm"
  289.    u -i l -d ~/nd -y h
  290. - Testing find args using type and regex and case sensitivity off
  291.       ./js/DO_NOT_UPLOAD_royalSliderSrc/templates/ajax-sliders/simple-slider.html
  292.    cd ~/nd ; find . -type f -iregex ".*TEMPLATES.*slider.html"
  293.    u -i l -d ~/nd -y h ".*TEMPLATES.*slider.html"
  294. - Testing grep args
  295.       cd ~ ; find . -type f -name "va*.vim" -iregex ".*ator.*"
  296.       u -i l -d ~ -f "va*.vim" ".*ator.*" -s
  297.       u -i l -d ~ "va.*ator.*.*vim" -s
  298. - Testing gep args with or conditions to target file names, NOT paths
  299.       cd ~ ; find . -type f -name "cof*.vim" -o -name "caf*.vim"
  300.       u -i l -d ~ -f "*.vim" "/cof.*\.vim" "/caf.*\.vim"
  301. - Testing gep args with or conditions to target file names AND paths
  302.       cd ~ ; find . -type f -iregex ".*COF.*.vim" -o -iregex ".*caf.*.vim"
  303.       u -i l -d ~ -f "*.vim" "COF.*\.vim" "caf.*\.vim"
  304. - Everything - should be the same number of files
  305.    cd ~ ; find . -type f -not -iwholename "*.svn*" -not -iwholename "*.bak*" -not -iwholename "*.class*" | wc -l
  306.    u -i l -d ~ | wc -l
  307. - bak or not to bak - should be the same number of files
  308.    - Set up test dir.
  309.       rm -rf /tmp/temptest
  310.       mkdir /tmp/temptest
  311.       cd /tmp/temptest
  312.       touch firstFile.txt
  313.       touch firstFile.bak
  314.    - Should show the same result
  315.       find . -name "*.txt"
  316.       u -i l -d /tmp/temptest -y t
  317.    - Should show the same result
  318.       find . -name "*.bak"
  319.       u -i l -d /tmp/temptest -y E bak
  320. STOP_HELP
  321. }
  322.  
  323. # ===  FUNCTION  ===============================================================
  324. #   DESCRIPTION:  Process all arguments to script. How to handle getopts args
  325. #                 and operands at the same time:
  326. #                    http://stackoverflow.com/a/21169366/257233
  327. #    PARAMETERS:  -
  328. #       RETURNS:  -
  329. # ==============================================================================
  330. function processArguments() {
  331.    # Loop to handle all parameters
  332.    non_option_parameters=()
  333.    while true; do
  334.       # Process single letter args.
  335.       while getopts "$OPTIONS" option; do
  336.          if ! processSingleLetterArguments "$option"; then exit 9; fi
  337.       done
  338.       if ((OPTIND > $#)); then break; fi
  339.       non_option_parameters+=(${!OPTIND})
  340.       # Handle operand arg - arrayOfFilesFromCommandLine not handled by getopts
  341.       arrayOfFilesFromCommandLine+=("${!OPTIND}")
  342.      ((OPTIND++))
  343.    done
  344.  
  345.    # ---------------------------------------------------------------------------
  346.    # Post argument processing - logic that must be applied once we know all args.
  347.    # ---------------------------------------------------------------------------
  348.    # Figure out find command.
  349.    findForm=
  350.    if [ "$caseSensitive" = "yes" -a "$findArgRegex" = "yes" ] ; then
  351.       findForm="-regex"
  352.    elif [ "$caseSensitive" = "yes" -a "$findArgRegex" = "no" ] ; then
  353.       findForm="-name"
  354.    elif [ "$caseSensitive" = "no" -a "$findArgRegex" = "yes" ] ; then
  355.       findForm="-iregex"
  356.    elif [ "$caseSensitive" = "no" -a "$findArgRegex" = "no" ] ; then
  357.       findForm="-iname"
  358.    else
  359.       usage "Am in impossible condition. Exit."
  360.       exit 44
  361.    fi
  362.    findArg=("${symbolic}" '.' "${excludeParams[@]}" '-type' 'f' "$findForm" "$filePattern")
  363.  
  364.    # Figure out grep command.
  365.    if [ "$caseSensitive" = "yes" ] ; then
  366.       grepArg=( '' )
  367.    else
  368.       grepArg=( '-i' )
  369.    fi
  370.  
  371.  
  372. }
  373.  
  374. # ===  FUNCTION  ===============================================================
  375. #   DESCRIPTION:  Process single letter args via getopts
  376. #    PARAMETERS:  -
  377. #       RETURNS:  -
  378. # ==============================================================================
  379. OPTIONS=":bd:e:f:F:hi:L:m:svy:"
  380. function processSingleLetterArguments() {
  381.    case "$1" in
  382.       b ) symbolic="-L";;
  383.       d ) baseDir="$OPTARG";;
  384.       e ) validateEditorChoice "$OPTARG";;
  385.       f ) filePattern="$OPTARG";;
  386.       F ) filePattern="$OPTARG";
  387.             findArgRegex=yes;;
  388.       h ) usage; exit 0;;
  389.       i ) setUpInteractivity "$OPTARG";;
  390.       L ) searchTermLess="$OPTARG";;
  391.       m ) minFilesInteractive="$OPTARG";;
  392.       s ) caseSensitive=yes;;
  393.       v ) verbose=yes;;
  394.       y ) processFileType "$OPTARG";;
  395.       \?)   usage "*** Invalid option: -$OPTARG ***"; exit 10;;
  396.       :)    usage "*** Option -$OPTARG requires an argument. ***"; exit 11;;
  397.    esac
  398. }
  399.  
  400. # ===  FUNCTION  ===============================================================
  401. #   DESCRIPTION:  Process choice of what type of file to look through?
  402. #                 Analyses filePattern and filePatternType variables.
  403. #                 Note: code shared by search.sh and u.sh. So if you modify one,
  404. #                 make the same change to the other Rob!
  405. #    PARAMETERS:  Potential filePattern
  406. #       RETURNS:  -
  407. # ==============================================================================
  408. function processFileType() {
  409.    case "${1}" in
  410.       a) filePattern='*.js';;
  411.       b) filePattern='*.php';;
  412.       c) filePattern='*.css';;
  413.       d) filePattern='*.sh';;
  414.       e) filePattern='*.*';;
  415.       E) filePattern='*.*';
  416.          excludeParams=();;
  417.       h) findArgRegex=yes;
  418.          filePattern='.*.htm[l]?';;
  419.       i) filePattern='*.idx';;
  420.       j) filePattern='*.java';;
  421.       l) filePattern='*.sh';;
  422.       p) findArgRegex=yes;
  423.          filePattern='.*[.]jsp[h]?';;
  424.       r) filePattern='*.properties';;
  425.       s) filePattern='*.sql';;
  426.       t) filePattern='*.txt';;
  427.       x) filePattern='*.xml';;
  428.       z) findArgRegex=yes;
  429.          filePattern='.*[.]\(jsp[h]?\|java\|properties\)';;
  430.       *) usage "*** Unknown -type: $filePatternType. ***"; exit 3;;
  431.    esac
  432. }
  433.  
  434. # ===  FUNCTION  ===============================================================
  435. #   DESCRIPTION:  Process command line arg governing interactivity.
  436. #    PARAMETERS:  interactivity flag
  437. #       RETURNS:  -
  438. # ==============================================================================
  439. function setUpInteractivity() {
  440.    case "$1" in
  441.       "F" | "f" ) interactivityMode="F";;
  442.       "L" | "l" ) interactivityMode="L";;
  443.       "N" | "n" ) interactivityMode="N";;
  444.       "P" | "p" ) interactivityMode="P";;
  445.       *         ) usage "Invalid option for -i. [F]ull, [L]imited or [N]one."; exit 2;;
  446.    esac
  447. }
  448.  
  449. # ===  FUNCTION  ===============================================================
  450. #   DESCRIPTION:  Process command line arg governing minFilesInteractive.
  451. #    PARAMETERS:  minFilesInteractive flag
  452. #       RETURNS:  -
  453. # ==============================================================================
  454. function setUpMinFilesInteractive() {
  455.    if [ -n "`echo "$1" | grep -E -e '^[0-9]+$'`" ]
  456.    then
  457.       minFilesInteractive="$1"
  458.    else
  459.       usage "Invalid option for -m; not a number."
  460.       exit 3
  461.    fi
  462. }
  463.  
  464. # ===  FUNCTION  ===============================================================
  465. #   DESCRIPTION:  Work out what editor to use if the user didn't specify one.
  466. #                 Set the path to that editor in a script variable, "editor".
  467. #    PARAMETERS:  editor flag
  468. #       RETURNS:  -
  469. # ==============================================================================
  470. function validateEditorChoice() {
  471.    case "$1" in
  472.       "e" | "E" ) editor="e";;
  473.       "u" | "U" ) editor="u";;
  474.       "l" | "L" ) editor="l";;
  475.       "o" | "O" ) editor="o";;
  476.       "v" | "V" ) editor="v";;
  477.       *         ) usage "Invalid option for -e. $editorChoiceMessage"; exit 4;;
  478.    esac
  479. }
  480.  
  481.  
  482. # ===  FUNCTION  ===============================================================
  483. #   DESCRIPTION:  Output all the arguments we have if verbose is turned on.
  484. #                 Outputs most variables in script.
  485. #    PARAMETERS:  -
  486. #       RETURNS:  -
  487. # ==============================================================================
  488. function outputAllArgs() {
  489.    if [ "$verbose" == "yes" ] ; then
  490.       echo "--- List of args -----------------------------------------"
  491.       echo "Arg arrayOfFilesFromCommandLine: [${arrayOfFilesFromCommandLine[@]}]"
  492.       echo "Arg baseDir: [${baseDir}]"
  493.       echo "Arg caseSensitive: [${caseSensitive}]"
  494.       echo "Arg commandName: [${commandName}]"
  495.       echo "Arg editor: [${editor}]"
  496.       echo "Arg editorChoiceMessage: [${editorChoiceMessage}]"
  497.       echo "Arg excludeParams: [${excludeParams[@]}]"
  498.       echo "Arg filePattern: [${filePattern}]"
  499.       echo "Arg findArg: [${findArg[@]}]"
  500.       echo "Arg findArgRegex: [${findArgRegex}]"
  501.       echo "Arg grepArg: [${grepArg[@]}]"
  502.       echo "Arg interactivityMode: [${interactivityMode}]"
  503.       echo "Arg minFilesInteractive: [${minFilesInteractive}]"
  504.       echo "Arg searchPerformed: [${searchPerformed}]"
  505.       echo "Arg searchTermLess: [${searchTermLess}]"
  506.       echo "Arg symbolic: [${symbolic}]"
  507.       echo "Arg verbose: [${verbose}]"
  508.       echo "----------------------------------------------------------"
  509.    fi
  510. }
  511.  
  512. # ===  FUNCTION  ===============================================================
  513. #   DESCRIPTION:  Open files that have been selected - filesToOpen must contain
  514. #                 a list of space separated indexes to the associative array of
  515. #                 files, fileSet.
  516. #    PARAMETERS:  -
  517. #       RETURNS:  -
  518. # ==============================================================================
  519. function openSelectedFiles() {
  520.    # Create new array out of selected files.
  521.    newFileSet=()
  522.    for nextIndex in $filesToOpen ; do
  523.       case "$nextIndex" in
  524.         *[!0-9]*|""   ) echo "Not a valid index: $nextIndex";;
  525.         *             ) newFileSet+=("${fileSet[$nextIndex]}");;
  526.       esac      #  Allows ranges of characters in [square brackets],
  527.    done
  528.    unset fileSet
  529.    fileSet=( "${newFileSet[@]}" )
  530.    openAllFiles
  531. }
  532.  
  533. # ===  FUNCTION  ===============================================================
  534. #   DESCRIPTION:  Open all files in the array of files, fileSet. This must be
  535. #                 the ONLY method that actually opens files.
  536. #    PARAMETERS:  -
  537. #       RETURNS:  -
  538. # ==============================================================================
  539. function openAllFiles() {
  540.    if [ ${#fileSet[@]} -eq 0 ] ; then
  541.       echo "No files to open."
  542.       exit 5
  543.    fi
  544.    case "$editor" in
  545.       e )   convertFileSetToWindowsPaths     # Eclipse
  546.             $ECLIPSE --launcher.openFile \
  547.                   "${fileSet[@]}" & ;;
  548.       l )   if [ -z "$searchTermLess" ] ; then
  549.                less "${fileSet[@]}"            # less
  550.             else
  551.                less -I -p "${searchTermLess}" "${fileSet[@]}"
  552.             fi
  553.             ;;
  554.       o )                                    # notepad
  555.             for index in "${!fileSet[@]}" ; do
  556.                notepad "${fileSet[$index]}" &
  557.             done ;;
  558.       u )   convertFileSetToWindowsPaths     # UltraEdit
  559.             "$UEDIT" "${fileSet[@]}" & ;;
  560.       v )   if [ -z "$searchTermLess" ] ; then
  561.                vim ${fileSet[@]}             # vim
  562.             else
  563.             echo ######################################### search for searchTermLess: $searchTermLess
  564.                vim +/"${searchTermLess}" ${fileSet[@]}
  565.             fi
  566.             ;;
  567.       * )   usage "Unknown editor option [$editor]. How did you even get here?" ; exit 6;;
  568.    esac
  569. }
  570.  
  571. # ===  FUNCTION  ===============================================================
  572. #   DESCRIPTION:  Convert array of paths in Cygwin format to Windows format.
  573. #                 Modified fileSet in place.
  574. #    PARAMETERS:  -
  575. #       RETURNS:  -
  576. # ==============================================================================
  577. function convertFileSetToWindowsPaths() {
  578.    index=0
  579.    while [ "${index}" -lt "${#fileSet[@]}" ]
  580.    do
  581.       # echo File [${index}]: ${fileSet[$index]}
  582.       fileSet[$index]=`cygpath -w -a "${fileSet[$index]}"`
  583.       let "index++"
  584.    done
  585. }
  586.  
  587. # ===  FUNCTION  ===============================================================
  588. #   DESCRIPTION:  Print list of files in the set - printing index for each entry.
  589. #    PARAMETERS:  -
  590. #       RETURNS:  -
  591. # ==============================================================================
  592. function printListOfFilesWithIndex() {
  593.    index=0
  594.    while [ "${index}" -lt "${#fileSet[@]}" ]
  595.    do
  596.       printf "File %*d: %s\n" 2 ${index} "${fileSet[$index]}"
  597.       let "index++"
  598.    done
  599. }
  600.  
  601. # ===  FUNCTION  ===============================================================
  602. #   DESCRIPTION:  Print list of files in the set - without an index for each entry.
  603. #    PARAMETERS:  -
  604. #       RETURNS:  -
  605. # ==============================================================================
  606. function printListOfFilesWithoutIndex() {
  607.    index=0
  608.    while [ "${index}" -lt "${#fileSet[@]}" ]
  609.    do
  610.       echo "${fileSet[$index]}"
  611.       let "index++"
  612.    done
  613. }
  614.  
  615. # ===  FUNCTION  ===============================================================
  616. #   DESCRIPTION:  Find files from the file name arguments to this script.
  617. #                 Each argument could be a
  618. #                    - valid relative path to a file from base dir.
  619. #                    - valid absolute path to a file.
  620. #                    - regular expression to be used to grep over results of a find.
  621. #                 Fill up a variable called fileSet with the results.
  622. #    PARAMETERS:  -
  623. #       RETURNS:  -
  624. # ==============================================================================
  625. function getFilesFromFindAndGrep() {
  626.    fileIndex=0
  627.    # Go through file arguments.
  628.    for index in ${!arrayOfFilesFromCommandLine[@]} ; do
  629.       # If the argument is a file path that exists, put it in the file set
  630.       if [ -f "${arrayOfFilesFromCommandLine[$index]}" ] ; then
  631.          # echo File path: "${arrayOfFilesFromCommandLine[$index]}"
  632.          fileSet[$fileIndex]="${arrayOfFilesFromCommandLine[$index]}"
  633.          let "fileIndex++"
  634.       else
  635.       # Otherwise, treat argument as a regular expression to modify superset of
  636.       # files - which is itself the result of a find command.
  637.          # We are searching..
  638.          searchPerformed=Y
  639.          message "RUNNING find ${findArg[@]} | grep ${grepArg[@]} ${arrayOfFilesFromCommandLine[$index]}"
  640.          files=`find "${findArg[@]}" | grep ${grepArg[@]} "${arrayOfFilesFromCommandLine[$index]}"`
  641.          # Put each file we found into file set.
  642.          for file in $files ; do
  643.              # echo File from expressio: "$file"
  644.             fileSet[$fileIndex]="$file"
  645.             let "fileIndex++"
  646.          done
  647.       fi
  648.    done
  649. }
  650.  
  651. # ===  FUNCTION  ===============================================================
  652. #   DESCRIPTION:  Find files using only a find - no grep, no file paths.
  653. #                 Fill up a variable called fileSet with the results.
  654. #    PARAMETERS:  -
  655. #       RETURNS:  -
  656. # ==============================================================================
  657. function getFilesFromFind() {
  658.    # No trailing args - we are searching..
  659.    searchPerformed=Y
  660.    message "RUNNING find ${findArg[*]}"
  661.  
  662.    files=`find "${findArg[@]}"`
  663.  
  664.    # Put each file we found into file set.
  665.    for file in $files ; do
  666.       # echo File from expression "$file"
  667.       fileSet[$fileIndex]="$file"
  668.       let "fileIndex++"
  669.    done
  670.  
  671. }
  672.  
  673. # ===  FUNCTION  ===============================================================
  674. #   DESCRIPTION:  Display list of files and ask user which ones to open. Puts
  675. #                 their answer into variable called fileToOpen.
  676. #    PARAMETERS:  -
  677. #       RETURNS:  -
  678. # ==============================================================================
  679. function askUserWhatFilesToOpen() {
  680.    printListOfFilesWithIndex
  681.    echo ----
  682.    echo Specify files to open. [A]ll, [N]one or [x y z] space separated indexes.
  683.    echo Can also override editor choice. $editorChoiceMessage
  684.    read filesToOpen
  685.    # echo We will open these: ${filesToOpen}
  686.  
  687.    newFilesToOpen=
  688.    openNoFiles=no
  689.    openAllFiles=no
  690. # Reset separator to what it was.
  691. IFS="$oldIFS"
  692.  
  693.    for word in $filesToOpen ; do
  694.       case "${word}" in
  695.          "e" | "u" | "l" | "o" | "v" | "E" | "U" | "L" | "O" | "V")
  696.                         editor=${word}
  697.                         message "Changing editor to ${word}";;
  698.          "n" | "N")     openNoFiles="yes";;
  699.          "a" | "A")     openAllFiles="yes";;
  700.          *[!0-9]*|"" )  echo "Not a valid index: $word";;
  701.          *           )  newFilesToOpen+=" ${word}";;
  702.       esac
  703.    done
  704.  
  705.    if [ "$openNoFiles" = "yes" ] ; then
  706.       message "You chose to open no files. Done."
  707.       exit 0
  708.    fi
  709.    if [ "$openAllFiles" = "yes" ] ; then
  710.       message "You chose to open all files."
  711.       openAllFiles
  712.       exit 0
  713.    fi
  714.    if [ -z "$newFilesToOpen" ] ; then
  715.       message "No files to open (or all indexes were invalid)."
  716.       exit 7
  717.    else
  718.       message "Opening files based on selected indexes: $newFilesToOpen"
  719.       filesToOpen="$newFilesToOpen"
  720.       openSelectedFiles
  721.    fi
  722. }
  723.  
  724. # ------------------------------------------------------------------------------
  725. # -- Script Logic
  726. # ------------------------------------------------------------------------------
  727.  
  728. # Process all the arguments.
  729. processArguments "$@"
  730.  
  731. cd "$baseDir"
  732.  
  733. outputAllArgs
  734.  
  735.    # Make delimiter equal to whatever newline char we are using now
  736.    oldIFS=$IFS
  737. # MUST keep this aligned to edge like this to correctly interpret new line.
  738. IFS="
  739. "
  740.  
  741.  
  742. if [ "${#arrayOfFilesFromCommandLine[@]}" -eq 0 ] ; then
  743.    message "Get files from file pattern."
  744.    getFilesFromFind
  745. else
  746.    message "Get files from command line."
  747.    getFilesFromFindAndGrep
  748. fi
  749.  
  750.  
  751. if [ ${#fileSet[@]} -eq 0 ]
  752. then
  753.    echo No files found.
  754.    exit 0
  755. fi
  756.  
  757. # Just list the files?
  758. if [ "$interactivityMode" = "L" ]
  759. then
  760.    printListOfFilesWithoutIndex
  761.  
  762. # Open all of the files without asking? Interactive mode is [N]one.
  763. elif  [ "$interactivityMode" = "N" ] ; then
  764.    openAllFiles
  765.  
  766. # Interactive mode is [P]Artial.
  767. # Ask the user what files to open if no search was performed or if number of
  768. # files found was less than min required to trigger interactivity.
  769. elif  [ "$interactivityMode" = "P" ] ; then
  770.    if [ "${#fileSet[@]}" -lt "$minFilesInteractive" -o "$searchPerformed" = "N" ]
  771.    then
  772.       openAllFiles
  773.    else
  774.       askUserWhatFilesToOpen
  775.    fi
  776.  
  777. # Interactive mode is [F]ull.
  778. # Ask the user what files to open if we are in interactive mode.
  779. else
  780.    askUserWhatFilesToOpen
  781. fi
  782.  
  783. # echo Done.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement