shell小工具:findstr 和 findfile

Linux下常用find+grep的组合来查找字符串或文件,但每次都要输入很长的命令,很是麻烦。下面的两个shell脚本类似对find+grep的组合命令的包装,可用于简单快速地从指定文件夹下查找字符串、宏定义、struct、class、typedef声明、以及查找指定文件。

1、查找字符串、宏、结构体、类、typedef语句shell脚本(findstr):

#! /bin/bash

Usage()
{
    echo "Usage: ${0##*/} [option] [path] search-content"
    echo "[Options]:"
    echo "  -S,--string               search string"
    echo "  -m,--macro                search macro define"
    echo "  -t,--typedef              search typedef statement"
    echo "  -c,--class                search class declare"
    echo "  -s,--struct               search class declare"
    echo "  -E,--extended-regexp      support grep extended regular expression"
    echo "  -i,--ignore-case          ignore search-content case"
    echo "  -e,--exclude-dir=dirlist  ignore directory whose name is in the excluding list(separated by :)"
    echo "  -h,--help                 display help information"
    echo "[Note]: If you don't specify path, default searching from current directory."
}

if [ $# -eq 0 ]; then
  Usage
  exit 1
fi

while [ $# -gt 0 ]; do
    case $1 in
    -*)
        case $1 in
        -S|--string)
            SEARCH_TYPE="string";;
        -m|--macro)
            SEARCH_TYPE="macro";;
        -t|--typedef)
            SEARCH_TYPE="typedef";;
        -c|--class)
            SEARCH_TYPE="class";;
        -s|--struct)
            SEARCH_TYPE="struct";;
        -E|--extended-regexp)
            GREP_EXT_REG_OPTION="-E";;
        -i|--ignore-case)
            GREP_IGNORE_CASE_OPTION="-i";;
        -e|--exclude-dir=*)
            if [ -n "$EXCLUDE_DIR_LIST" ]; then
                echo "Invalid usage: double specify excluding dirs!"
                exit 1
            fi
            if [ "$1" = "-e" ]; then
                shift
                if [ "${1:1:1}" = "-" ]; then
                    echo "Invalid usage: no dirname behind -e option!"
                    exit 1
                else
                    EXCLUDE_DIR_LIST=":$1:"    # add : at both sides
                fi
            else
                EXCLUDE_DIR_LIST=":${1#*=}:"
            fi;;
        -h|--help)
            Usage
            exit 0;;
        *)
            echo "Invalid usage: unknown option $1!"
            exit 1;;
        esac ;;
    *)
        if [ -d "$1" ]; then
            if [ -z "$SEARCH_PATH" ]; then
                SEARCH_PATH="$1"
            elif [ -z "$SEARCH_CONTENT" ]; then
                SEARCH_CONTENT="$1"
            else
                echo "Invalid usage: too many directory parameters!"
                exit 1
            fi
        elif [ -z "$SEARCH_CONTENT" ]; then
            SEARCH_CONTENT="$1"
        else
            echo "Invalid usage: too many search-content parameters!"
            exit 1
        fi ;;
    esac
    shift
done

GREP_EXTRAL_OPTION="-n -H --color $GREP_EXT_REG_OPTION $GREP_IGNORE_CASE_OPTION"

if [ -z $SEARCH_TYPE ]; then
    SEARCH_TYPE="string"
fi
  
if [ -z "$SEARCH_CONTENT" ]; then
    # perhaps the content to be searched is a path-style name, and not specify path parameter
    if [ -n "$SEARCH_PATH" ]; then
        SEARCH_CONTENT="$SEARCH_PATH"
        SEARCH_PATH="."
    else
        echo "Invalid usage: no search-content parameter!"
        exit 1
    fi
fi

if [ -z "$SEARCH_PATH" ]; then
    SEARCH_PATH="."
fi

SearchString()
{
    # ignore /dev direcotry
    if [ "${PWD:0:4}" = "/dev" ]; then
        echo -e "\e[31mWarning:\e[m\e[33m ignored direcotry $PWD\e[m"
        return 
    fi
    for file in `ls`; do
        if [ -d $file ]; then
            # prevent symbol link which links to its parent directory (lineal consanguinity)
            if [ -L $file ]; then
                FUN_SS_BASE_PWD_P=$(pwd -P)
                FUN_SS_SUBDIR_PWD_P=$(cd ./$file; pwd -P)
                if [ "${FUN_SS_BASE_PWD_P#$FUN_SS_SUBDIR_PWD_P}" != "${FUN_SS_BASE_PWD_P}" ]; then
                    continue
                fi
            fi
            if [ "${EXCLUDE_DIR_LIST/:$file:/}" != "${EXCLUDE_DIR_LIST}" ]; then
                continue
            fi
            cd ./$file # add "./" for those special directories whose name begin with "-"
            SearchString
            cd ..
            continue
        fi
        if [ ! -f $file -o ! -r $file ]; then
            echo -e "\e[31mWarning:\e[m\e[33m ignored file $PWD/$file\e[m"
        fi
        if grep $GREP_EXTRAL_OPTION "$SEARCH_CONTENT" "`pwd`/$file" ; then
            let "SEARCH_MATCH_COUNT+=1"
        fi
    done
}

Search()
{
    # ignore /dev direcotry
    if [ "${PWD:0:4}" = "/dev" ]; then
        echo -e "\e[31mWarning:\e[m\e[33m ignored direcotry $PWD\e[m"
        return 
    fi
    for file in `ls`; do
        if [ -d $file ]; then
            # prevent symbol link which links to its parent directory (lineal consanguinity)
            if [ -L $file ]; then
                FUN_S_BASE_PWD_P=$(pwd -P)
                FUN_S_SUBDIR_PWD_P=$(cd ./$file; pwd -P)
                if [ "${FUN_S_BASE_PWD_P#$FUN_S_SUBDIR_PWD_P}" != "${FUN_S_BASE_PWD_P}" ]; then
                    continue
                fi
            fi
            if [ "${EXCLUDE_DIR_LIST/:$file:/}" != "${EXCLUDE_DIR_LIST}" ]; then
                continue
            fi
            cd $file
            Search
            cd ..
            continue
        fi
        
        if [ ! -f $file -o ! -r $file ]; then
            echo -e "\e[31mWarning:\e[m\e[33m ignored file $PWD/$file\e[m"
        fi
        
        case $SEARCH_TYPE in
        macro)
            if grep $GREP_EXTRAL_OPTION "#[[:space:]]*define[[:space:]]*$SEARCH_CONTENT" "`pwd`/$file" ; then
                let "SEARCH_MATCH_COUNT+=1"
            fi;;
        typedef)
            if grep $GREP_EXTRAL_OPTION "typedef.*$SEARCH_CONTENT" "`pwd`/$file" ; then
                let "SEARCH_MATCH_COUNT+=1"
            fi;;
        class)
            if grep $GREP_EXTRAL_OPTION "class.*$SEARCH_CONTENT" "`pwd`/$file" ; then
                let "SEARCH_MATCH_COUNT+=1"
            fi;;
        struct)
            if grep $GREP_EXTRAL_OPTION "struct.*$SEARCH_CONTENT" "`pwd`/$file" ; then
                let "SEARCH_MATCH_COUNT+=1"
            fi;;
        *)
            if grep $GREP_EXTRAL_OPTION "$SEARCH_CONTENT" "`pwd`/$file" ; then
                let "SEARCH_MATCH_COUNT+=1"
            fi;;
        esac
    done
}

pushd $SEARCH_PATH > /dev/null
SEARCH_MATCH_COUNT=0
if [ "$SEARCH_TYPE" = "string" ]; then
    SearchString
else
    Search
fi
if [ $SEARCH_MATCH_COUNT -lt 1 ]; then
    echo -e "No $SEARCH_TYPE matches \033[40;31m$SEARCH_CONTENT\033[0m in \033[40;31m$SEARCH_PATH\033[0m directory and its sub-directory!"
fi
popd > /dev/null

【说明】: (1) 此脚本不能跨行操作,因此对于定义为多行的(如:关键字class与其类名不在同一行的)查找内容会失效。
           (2) 此脚本考虑到效率问题,对符号链接若有死循环支持不够,只支持类似“直系血亲”的死循环检测。(后面的findfile脚本中SearchFile2提供了一种检测符号链接若有死循环的方法,不过效率不高,默认情况也不使用它。)

2、查找文件shell脚本(findfile):

#!/bin/bash

Usage()
{
    echo "Usage: ${0##*/} [option] [path] filename"
    echo "  -a,--absolute  dispaly absolute path (default)"
    echo "  -r,--relative  dispaly relative path"
    echo "  -e,--exact     the filename must be exactly matches"
    echo "  -h,--help      display this information"
    echo "[Note]: If you don't specify any option, -a will be used by default."
}

if [ $# -eq 0 ]; then
    echo "Invalid usage: no filename specified!"
    exit 1
fi

while [ $# -gt 0 ]; do
    case $1 in
    -*)
        # ignore duplicated and conflicted options
        case $1 in
        -a|--absolute)
            FLAG_ABSOLUTE_PATH="true"
            ;;
        -r|--relative)
            FLAG_ABSOLUTE_PATH="false"
            ;;
        -e|--exact)
            FLAG_EXACTLY_MATCH="true"
            ;;
        -h|--help)
            Usage
            exit 0
            ;;
        *)
            echo "Invalid usage: unknown option $1!"
            exit 1
            ;;
        esac ;;
    *)
        if [ -d "$1" ]; then
            if [ -z "$SEARCH_PATH" ]; then
                SEARCH_PATH="$1"
            elif [ -z "$SEARCH_FILE" ]; then
                SEARCH_FILE="$1"
            else
                echo "Invalid usage: too many directory parameters!"
                exit 1
            fi
        elif [ -z "$SEARCH_FILE" ]; then
            SEARCH_FILE="$1"
        else
            echo "Invalid use: too many filename parameters!"
            exit 1
        fi
        ;;
    esac
    shift
done

if [ -z $FLAG_ABSOLUTE_PATH ]; then
    FLAG_ABSOLUTE_PATH="true"
fi

if [ -z "$SEARCH_FILE" ]; then
    # perhaps the filename to be searched is a path-style name, and not specify path parameter
    if [ -n "$SEARCH_PATH" ]; then
        SEARCH_FILE="$SEARCH_PATH"
        SEARCH_PATH="."
    else
        echo "Invalid usage: no filename specified!"
        exit 1
    fi
fi

if [ -z "$SEARCH_PATH" ]; then
  SEARCH_PATH="."
fi

SearchFile()
{
    for file in `ls`; do
        if [ -d $file ]; then
            # prevent symbol link which links to its parent directory (lineal consanguinity)
            if [ -L $file ]; then
                FUN_SF_BASE_PWD_P=$(pwd -P)
                FUN_SF_SUBDIR_PWD_P=$(cd ./$file; pwd -P)
                if [ "${FUN_SF_BASE_PWD_P#$FUN_SF_SUBDIR_PWD_P}" != "${FUN_SF_BASE_PWD_P}" ]; then
                    continue
                fi
            fi

            if [ "$FLAG_EXACTLY_MATCH" = "true" ]; then
                if [ "$file" = "$SEARCH_FILE" ]; then
                    echo -e "$PWD/\e[34m$file\e[m"
                fi
            elif [ "${file/$SEARCH_FILE/}" != "${file}" ]; then
                echo -e "$PWD/${file/$SEARCH_FILE/\e[34m$SEARCH_FILE\e[m}"
            fi
            
            cd ./$file
            SearchFile
            cd ..
            continue
        fi
        
        if [ "$FLAG_EXACTLY_MATCH" = "true" ]; then
            if [ "$file" = "$SEARCH_FILE" ]; then
                echo -e "$PWD/\e[34m$file\e[m"
            fi
        elif [ "${file/$SEARCH_FILE/}" != "$file" ]; then
            echo -e "$PWD/${file/$SEARCH_FILE/\e[34m$SEARCH_FILE\e[m}"
        fi
    done
}

cd $SEARCH_PATH
SearchFile

## PHYSICAL_PATH_LIST must be initialized as :$(cd $SEARCH_PATH; pwd -P): before calling SearchFile2()
## considered the case: dead loop of symbol link
#SearchFile2()
#{
#    for file in `ls`; do
#        if [ -d $file ]; then
#            cd ./$file
#            FUN_SF_SON_PWD_P=$(pwd -P)
#            if [ "${PHYSICAL_PATH_LIST/:$FUN_SF_SON_PWD_P:/}" != "${PHYSICAL_PATH_LIST}" ]; then
#                cd ..
#                continue
#            fi
#            PHYSICAL_PATH_LIST=${PHYSICAL_PATH_LIST}${FUN_SF_SON_PWD_P}:
#
#            if [ "$FLAG_EXACTLY_MATCH" = "true" ]; then
#                if [ "$file" = "$SEARCH_FILE" ]; then
#                    echo -e "$PWD/\e[34m$file\e[m"
#                fi
#            elif [ "${file/$SEARCH_FILE/}" != "${file}" ]; then
#                echo -e "$PWD/${file/$SEARCH_FILE/\e[34m$SEARCH_FILE\e[m}"
#            fi
#            
#            SearchFile2
#            PHYSICAL_PATH_LIST=${PHYSICAL_PATH_LIST%:*:}:
#            cd ..
#            continue
#        fi
#        
#        if [ "$FLAG_EXACTLY_MATCH" = "true" ]; then
#            if [ "$file" = "$SEARCH_FILE" ]; then
#                echo -e "$PWD/\e[34m$file\e[m"
#            fi
#        elif [ "${file/$SEARCH_FILE/}" != "$file" ]; then
#            echo -e "$PWD/${file/$SEARCH_FILE/\e[34m$SEARCH_FILE\e[m}"
#        fi
#    done
#}
#
#cd $SEARCH_PATH
#PHYSICAL_PATH_LIST=:$(cd $SEARCH_PATH; pwd -P):
#SearchFile2
#
## The following implement has some questions on some platforms when search from /sys direcotry due to the use of -L option,
## but if not using -L option, it will ignored the symbol link which links to a direcotry 
#SearchFile3()
#{
#    # In some systems, find not support -L option (find: invalid predicate '-L')
#    find -L /usr -maxdepth 1 -name tmp > /dev/null 2>&1
#    if [ $? -eq 0 ]; then
#        FUN_SF_FIND_L_OPTION="-L"
#    else
#        FUN_SF_FIND_L_OPTION=""
#        echo -e "\e[31mWarning:\e[m\e[33m find command doesn't support -L option, it will not enter into symbol link direcotry to search.\e[m"
#    fi
#    
#    if [ "$FLAG_ABSOLUTE_PATH" = "true" ]; then
#        cd $SEARCH_PATH
#        FUN_SF_CURRENT_PATH=${PWD%/}
#        find $FUN_SF_FIND_L_OPTION . -type f | grep $SEARCH_FILE | sed "s,\./,$FUN_SF_CURRENT_PATH,g" | grep --color $SEARCH_FILE
#    else
#        find $FUN_SF_FIND_L_OPTION $SEARCH_PATH -type f | grep --color $SEARCH_FILE
#    fi
#}
#
#SearchFile3
原文地址:https://www.cnblogs.com/opangle/p/2595439.html