função bash para quebrar o argumento do programa e às vezes anexar

6

Estou interessado em uma solução geral, mas meu problema de exemplo específico é escrever uma função .bashrc que envolve o grep e anexa um caminho de arquivo ao comando, se estiver faltando. Basicamente, toda vez que o grep esperasse no stdin eu gostaria que ele buscasse um arquivo específico. Meu problema é como dizer (no invólucro) se o argumento final é um caminho a ser pesquisado versus, por exemplo, o padrão de pesquisa.

$ ls
example_file.txt
$ grep -someopts 'somestring' 'example_file.txt'

Finja que -someopts são, na verdade, opções válidas arbitrárias para o grep.
O argumento final é um padrão (a ser pesquisado) ou um arquivo (a ser pesquisado)?
Se somestring for um parâmetro para uma das opções, então example_file.txt será o padrão a ser procurado e grep aguardará stdin. Caso contrário, somestring é o padrão para procurar e example_file.txt será pesquisado.

No primeiro caso, quero anexar meu próprio arquivo a ser pesquisado no final do comando, mas não consigo detectar o referido caso sem falsos positivos. A única maneira parece ser que o wrapper considere todos os argumentos que o grep poderia ter.

Aqui está minha função de wrapper (onde check_has_path é o que preciso implementar):

function grep_wrapped() {
    if check_has_path ; then
        grep "$@"
    else
        grep "$@" '/default/filepath.txt'
    fi
}
    
por benxyzzy 06.10.2017 / 17:05

2 respostas

3

Abordagem: Separe as opções da linha de comando do padrão e os possíveis nomes de arquivos na linha de comando, depois conte os argumentos da linha de comando que não são opções. Se houver mais de um, execute o comando como está, caso contrário, marque no seu arquivo.

Em bash :

mygrep () {
    local -a opts

    while [ "$#" -gt 0 ]; do
        case "$1" in
            --) opts+=( "$1" ); shift; break ;;
            -*) opts+=( "$1" ) ;;
            *)  break
        esac
        shift
    done

    if [ "$#" -gt 1 ]; then
        grep "${opts[@]}" "$@"
    else
        grep "${opts[@]}" "$@" "/my/file"
    fi
}

A função separa as opções da linha de comando do restante da linha de comando e verifica se há mais de um argumento de linha de comando que não seja de opção (ou seja, algo diferente de um padrão). Se não houver, seu arquivo será marcado no final do comando.

Isso não funciona se você usar opções com argumentos de opção (por exemplo, -e PATTERN ), por isso é um pouco falho. Talvez possa servir como ponto de partida para outra pessoa?

Nos comentários, fica claro que o usuário não está interessado em executar grep , mas sim em pesquisar arquivos com uma extensão específica.

A seguinte função shell faz isso:

extfind () {
    local ext="$1"

    if [ -z "$ext" ]; then
        echo 'Missing extension' >&2
        return 1
    fi

    shift
    local dir="${1:-$HOME}"

    find "$dir" -type f -name "*.$ext"
}

Esta função seria usada como

$ extfind txt

para localizar todos os arquivos cujos nomes terminam com .txt no diretório inicial ou

$ extfind "[hc]" /usr/src

para localizar todos os arquivos cujos nomes terminam em .h ou .c no diretório /usr/src .

    
por 06.10.2017 / 18:56
1

Você pode usar uma espécie de teste pythonesque e, se houver uma exceção, fazer outra coisa. Algo como:

function grep_wrapped(){
    grep "$@" <&-
    local rc=$?
    if [ $rc = 2 ]      # probably a read error from closed stdin
    then   grep "$@" /default/filepath.txt
    else   return $rc
    fi
}

Deixa todo o trabalho para grep. Isso terá o efeito colateral da mensagem de erro

grep: (standard input): Bad file descriptor

quando você tem o código de saída 2 do grep porque stdin foi fechado. Você pode obviamente redirecionar o stderr para capturar este arquivo ou variável, e imprimi-lo se o código de retorno for 0 ou 1.

    
por 07.10.2017 / 18:04