写了个指定或排除文件名后再 git grep 的bash工具,

function gg-by-file {
    local usage="Usage:
    gg-by-file <file-filter> <text-pattern>

file-filter:
    include1[,include2...][~exclude1[,exclude2...]]

Matching:
    include : OR
    exclude : OR
    filename matching is case-insensitive

Examples:
    gg-by-file cpp printf
    gg-by-file cpp,h vector
    gg-by-file parser~test Token
    gg-by-file '*.cpp,*.hpp~test,temp' parse"

    #
    # help
    #
    case "$1" in
        -h|--help)
            printf '%s\n' "$usage"
            return 0
            ;;
    esac

    if (( $# < 2 )); then
        printf '%s\n' "$usage"
        return 1
    fi

    if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
        echo "Not inside a git repository."
        return 1
    fi

    local filter="$1"
    local pattern="$2"


    #
    # split include / exclude
    #
    local include="${filter%%~*}"
    local exclude=""

    [[ "$filter" == *'~'* ]] && exclude="${filter#*~}"


    #
    # validate
    #
    if [[ -z "$include" ||
          "$filter" == *'~~'* ||
          "$include" == ,* ||
          "$include" == *, ||
          "$exclude" == ,* ||
          "$exclude" == *, ]]; then
        echo "Invalid file-filter: $filter"
        return 1
    fi


    local -a inc exc files

    IFS=',' read -ra inc <<<"$include"

    if [[ -n "$exclude" ]]; then
        IFS=',' read -ra exc <<<"$exclude"
    fi


    local file file_lower kw kw_lower matched skip


    #
    # Single pass through git files
    #
    while IFS= read -r file
    do
        file_lower="${file,,}"


        #
        # include (OR)
        #
        matched=0

        for kw in "${inc[@]}"
        do
            kw_lower="${kw,,}"

            if [[ "$kw_lower" == *[\*\?]* ]]; then
                [[ "$file_lower" == $kw_lower ]]
            else
                [[ "$file_lower" == *"$kw_lower"* ]]
            fi || continue

            matched=1
            break
        done

        (( matched )) || continue


        #
        # exclude (OR)
        #
        skip=0

        for kw in "${exc[@]}"
        do
            [[ -z "$kw" ]] && continue

            kw_lower="${kw,,}"

            if [[ "$kw_lower" == *[\*\?]* ]]; then
                [[ "$file_lower" == $kw_lower ]]
            else
                [[ "$file_lower" == *"$kw_lower"* ]]
            fi || continue

            skip=1
            break
        done


        (( skip )) || files+=("$file")


    done < <(git ls-files)


    if (( ${#files[@]} == 0 )); then
        echo "No matching files."
        return 1
    fi


    #
    # Content search
    #
    git grep -nE --color=auto -- "$pattern" -- "${files[@]}"
}
3 个赞

{grep $1 $(git ls-files|grep -v $2|xargs)}

1 个赞

要这么长吗,有没有更简短一点的方案