Função que chama outra função com lista de argumentos não funciona

6

No meu .bash_aliases eu defini uma função que eu uso da linha de comando assim:

search -n .cs -n .cshtml -n .html SomeTextIWantToSearchFor /c/code/website/ /c/stuff/something/whatever/

A função constrói um comando grep que canaliza o resultado para outro comando grep (infelizmente confuso porque estou preso em uma versão antiga):

search() {
    local file_names opt OPTARG OPTIND pattern

    file_names=()
    while getopts ":n:" opt; do
        case $opt in
            n)
                file_names+=( "$OPTARG" )
                ;;
        esac
    done
    shift $((OPTIND-1))

    pattern="$1"
    shift

    if (( ${#file_names[@]} > 0 )); then
        file_names="${file_names[@]}"
        file_names=${file_names// /':\|'}:

        grep -I -r "$pattern" "$@" | grep "$file_names"
    else
        grep -I -r "$pattern" "$@"
    fi
}

Eu defini outra função que chama essa função:

search-some-set-of-files() {
    local file_names directories

    file_names=( "-n page1.cshtml" "-n page2.cshtml" "-n page3.cshtml" )

    directories=( "/c/code/website/" "/c/stuff/something/whatever/" )

    search "${file_names[@]}" "$@" "${directories[@]}"
}

Na linha de comando, eu chamo essa função assim:

search-some-set-of-files SomeTextIWantToSearchFor

Por algum motivo, os resultados incluem todos os arquivos nos diretórios de destino. Ou seja, os resultados não são filtrados pelo grep de acordo com os nomes de arquivo que eu especifiquei.

Se eu alterar a última linha da função search-some-set-of-files para ecoar o comando, obtenho isto:

$ search-some-set-of-files SomeTextIWantToSearchFor
search -n .cs -n .cshtml -n .html SomeTextIWantToSearchFor /c/code/website/ /c/stuff/something/whatever/

Qual é exatamente o que eu quero. Se eu copiar esse comando (ou digitá-lo na íntegra) na linha de comando, os resultados são como deveriam ser.

Se eu ativar o modo de depuração ( set -x ), posso ver que cada argumento está sendo citado separadamente pelo shell:

$ search-some-set-of-files SomeTextIWantToSearchFor
+ search-some-set-of-files SomeTextIWantToSearchFor
+ local file_names directories
+ file_names=("-n page1.cshtml" "-n page2.cshtml" "-n page3.cshtml")
+ directories=("/c/code/website/" "/c/stuff/something/whatever/")
+ search '-n page1.cshtml' '-n page2.cshtml' '-n page3.cshtml' SomeTextIWantToSearchFor /c/code/website/ /c/stuff/something/whatever/
+ return
+ etc...

Então eu acho que o problema está em como os argumentos estão sendo passados para a função search . Como faço para corrigir isso?

    
por David Kennedy 10.11.2014 / 19:56

1 resposta

6

Seu problema é o segundo grep :

... | grep "$file_names"

Quando você chama sua função, o espaço entre o -n e o nome do arquivo ( -n page1.cshtml ) é incluído na matriz $file_names . Então, a substituição:

file_names=${file_names// /':\|'}:

Adicionará um :\| extra no início da string devido ao espaço inicial. Então, seu segundo comando grep é, na verdade:

... | grep ":\|page1.cshtml:\|page2.cshtml:\|page3.cshtml:"

Como resultado, grep corresponde a todas linhas, pois todas as linhas de resultado incluirão filename: e isso corresponderá a : .

Então, uma solução fácil seria remover os espaços:

file_names=( "-npage1.cshtml" "-npage2.cshtml" "-npage3.cshtml" )

Tudo deve funcionar como esperado.

    
por 10.11.2014 / 20:30