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