Search code examples
shellgrepheadtailcat

bash script to automate searching for a string in code including sub-folders


I have been using a combination of tail, head and grep to print out code that is relavant to me. It helps me find functions and get straight to the point. I do this about 30 to 40 times a day so I thought i'd ask for some assistance on this since I am not good with sh scripting.

The command format I'd eventually like is something like giveme "searchstring" -nn << where nn is the number to give to head. err.. moving on

Below is what I am currently doing

grep -rl searchitem ./
cat ./filename | grep -n searchitem
tail -n +line ./filename | head -numberoflinestodisplay 


Example:

jezzy@forum:/var/www/sgs# grep -rl insert_into_selectbox ./
./bin/ext/js/functions_edit.js
./src/ext/js/functions_edit.js

jezzy@forum:/var/www/sgs# cat ./bin/ext/js/functions_edit.js | grep -n insert_into_selectbox
195:    for (key in data) insert_into_selectbox(selectbox, data[key], key, 0);
232:        insert_into_selectbox(selectbox, data[key], key,1);
273:    for (key in data) if (key!="_overload_") insert_into_selectbox(selectbox, data[key], key, 0);
289:function insert_into_selectbox(selectbox,text,value,selected) {
323:      insert_into_selectbox(id,right.value,right.value,1);
334:      insert_into_selectbox(id,options_right[i].text,options_right[i].value,1);


Then I choose one of the greps that works for me. I do not mind if the bash script does it for all occurrences of grep. It'll teach me to be more specific with my searches.


jezzy@forum:/var/www/sgs# tail -n +289 ./bin/ext/js/functions_edit.js | head -30
function insert_into_selectbox(selectbox,text,value,selected) {
  if (text=="" || value=="") return;
  var obj = getObj(selectbox);
  var index = _selectbox_find(obj, value);
  if (index == -1) {
        index = obj.options.length;
        obj.options[index] = new Option(text,value);
  }
  if (!obj.multiple && selected) obj.options[index].selected = true;
}


I think I could figure it out if I knew how to get all instances of the items found.

Merci and Thanks


Solution

  • You can try this script:

    #!/bin/bash
    
    shopt -s extglob
    
    SEARCHDIR_DEFAULT="./"
    
    read -ep "Enter search directory [$SEARCHDIR_DEFAULT]: " SEARCHDIR
    [[ $SEARCHDIR =~ ^[[:space:]]*$ ]] && SEARCHDIR=$SEARCHDIR_DEFAULT
    
    for (( ;; )); do
        read -p "Enter search item: " SEARCHITEM
        read -p "Enter number of lines to display: " NUMLINES
    
        readarray -t MATCHEDFILES < <(exec grep -rl "$SEARCHITEM" "$SEARCHDIR")
    
        echo "Please select a file to search into. Press C to cancel, or X to exit."
    
        select FILE in "${MATCHEDFILES[@]}"; do
            if [[ -n $FILE ]]; then
                readarray -t MATCHEDLINES < <(exec grep -n "$SEARCHITEM" "$FILE")
                echo "Please select starting line."
                select LINE in "${MATCHEDLINES[@]}"; do
                    if [[ -n $LINE ]]; then
                        LINENUM=${LINE%%:*}
                        tail -n "+$LINENUM" "$FILE" | head -n "$NUMLINES"
                    elif [[ $REPLY == [cC] ]]; then
                        break
                    elif [[ $REPLY == [xX] ]]; then
                        break 3
                    fi
                done
            elif [[ $REPLY == [cC] ]]; then
                break
            elif [[ $REPLY == [xX] ]]; then
                break 2
            fi
        done
    done
    

    New version:

    #!/bin/bash
    
    shopt -s extglob
    
    SEARCHDIR_DEFAULT="./"
    NUMLINES_DEFAULT=10
    
    for (( ;; )); do
        until
            read -ep "Enter search directory [$SEARCHDIR_DEFAULT]: " SEARCHDIR
            [[ $SEARCHDIR =~ ^[[:space:]]*$ ]] && SEARCHDIR=$SEARCHDIR_DEFAULT
            [[ -d $SEARCHDIR ]]
        do
            echo "Please enter a valid directory."
        done
        SEARCHDIR_DEFAULT=$SEARCHDIR
    
        until
            read -p "Enter search item: " SEARCHITEM
            [[ ! $SEARCHITEM =~ ^[[:blank:]]*$ ]]
        do
            echo "Please enter a valid search item."
        done
    
        until
            read -p "Enter number of lines to display [$NUMLINES_DEFAULT]: " NUMLINES
            [[ $NUMLINES =~ ^[[:space:]]*$ ]] && NUMLINES=$NUMLINES_DEFAULT
            [[ $NUMLINES =~ ^[[:digit:]]+$ && NUMLINES -gt 0 ]]
        do
            echo "Please enter a valid number of lines."
        done
        NUMLINES_DEFAULT=$NUMLINES
    
        readarray -t MATCHEDFILES < <(exec grep -rle "$SEARCHITEM" "$SEARCHDIR")
    
        P1="Please select a file to search into. [ENTER = show list again, C = cancel, X = exit]: "
        P2="Please select starting line. [ENTER = show list again, C = cancel, X = exit]: "
    
        PS3=$P1
    
        select FILE in "${MATCHEDFILES[@]}"; do
            if [[ -n $FILE ]]; then
                readarray -t MATCHEDLINES < <(exec grep -ne "$SEARCHITEM" "$FILE")
                if [[ ${#MATCHEDLINES[@]} -eq 0 || ! ${MATCHEDLINES[0]} =~ ^[[:digit:]]+: ]]; then
                    echo "No matching lines were extracted. Perhaps file is a binary."
                elif [[ ${#MATCHEDLINES[@]} -eq 1 ]]; then
                    LINENUM=${MATCHEDLINES[0]%%:*}
                    echo "----------------------------------------"
                    tail -n "+$LINENUM" "$FILE" | head -n "$NUMLINES"
                    echo "----------------------------------------"
                else
                    PS3=$P2
    
                    select LINE in "${MATCHEDLINES[@]}"; do
                        if [[ -n $LINE ]]; then
                            LINENUM=${LINE%%:*}
                            echo "----------------------------------------"
                            tail -n "+$LINENUM" "$FILE" | head -n "$NUMLINES"
                            echo "----------------------------------------"
                        elif [[ $REPLY == [cC] ]]; then
                            break
                        elif [[ $REPLY == [xX] ]]; then
                            break 3
                        fi
                    done
    
                    PS3=$P1
                fi
            elif [[ $REPLY == [cC] ]]; then
                break
            elif [[ $REPLY == [xX] ]]; then
                break 2
            fi
        done
    done