Eu quero pesquisar todas as funções definidas no bash por alguma string de pesquisa. O abaixo é um começo, mas quero então eliminar todos os termos que não são seguidos de espaço em branco na próxima linha (ou seja, eliminar todas as entradas que não foram encontradas $1
no corpo dessa função).
fu() { declare -f | grep -e \(\) -e $1; }
por exemplo, esta saída:
...
tt ()
untargz ()
urlfix ()
ver ()
[ -f /etc/lsb-release ] && RELEASE="$(cat /etc/lsb-release | grep DESCRIPTION | sed 's/^.*=//g' | sed 's/\"//g') ";
vi. ()
vi.su ()
...
reduziria a
...
ver ()
[ -f /etc/lsb-release ] && RELEASE="$(cat /etc/lsb-release | grep DESCRIPTION | sed 's/^.*=//g' | sed 's/\"//g') ";
...
Uma maneira ainda muito melhor (se possível) seria se todas as funções correspondentes pudessem ser determinadas e exibidas na íntegra.
Eu imagino isso mais ou menos como:
- Colete os nomes das funções com a string de pesquisa em seu corpo (o nome da função é sempre uma única palavra em uma linha antes da correspondência, começando em
^
seguido por um espaço e depois a linha terminando com()$
), depois usandocommand -V
em cada uma dessas names, OR, fazendo umdeclare -f
novamente, mas desta vez, usando esses nomes e combinando tudo depois deles de{
até}
(onde{
e}
estão em linhas únicas por si mesmos em^
- eu sei que grep/awk/sed pode fazer coisas incríveis para aqueles que têm esse conhecimento .
O resultado final estaria em execução fu awk
e me mostraria a definição de cada função que contém awk
no corpo da função.
O seguinte
awk
comando na extremidade receptora do pipe vem à mente:A ideia é armazenar a declaração e o corpo de cada função em um buffer
buf
enquanto analisa a saída dedeclare -f
, mas apenas imprimir o buffer se a string de pesquisa for encontrada.()
. Se uma correspondência foi encontrada durante a análise da função anterior (indicada pelo sinalizadorm
sendo 1), o bufferbuf
será impresso. Tanto o buffer quanto o sinalizador serão redefinidos.awk
variávelsrch
. Se for encontrado na linha atual (aindex
função retorna um resultado diferente de zero), om
sinalizador é definido como 1, mas somente se não estivermos na linha em que a declaração da função começa (indicada porbuf
não estar vazia), caso contrário, corresponde no nome da função também contaria.buf
e separada do conteúdo anterior pelo separador de registro de saídaORS
(que por padrão é nova linha).Observação
O programa executa uma pesquisa de string completa usando a
index()
função deawk
. Se você quiser que a pesquisa seja baseada na correspondência de expressões regulares, você precisará alterar a condição depara
(mas, como sempre, esteja ciente de que procurar strings que contenham caracteres que tenham significados especiais para expressões regulares se torna mais complicado).
Para aqueles que desejam fazer a mesma coisa em
zsh
, para obter as definições de funções cujo corpo corresponde a um padrão, você faria:o
<dummy>
para cobrir o caso em que não há função correspondente. Ou uma maneira mais limpa:Em
bash
, você poderia fazer algo semelhante com:Embora isso seja bastante ineficiente, pois a lista de nomes de funções é lida um byte por vez (já que
read
a entrada de ' é um pipe) e um processo é bifurcado para cada função. Pode ser otimizado com:readarray
, ao contrário deread
, não precisa ler a entrada um byte por vez, pois consome toda a entrada de qualquer maneira. Delimitamos as definições de função com caracteres NUL, pois de qualquer maneirabash
(ao contrário dezsh
) não podemos armazenar esse caractere em suas definições/nomes de função nem no conteúdo de variáveis e, em seguida, podemos usarreadarray -td ''
(o que requer bash-4.4+) para quebrá-lo em um array.Isso evita ter que confiar em heurísticas como a presença de
()
(que também pode ocorrer no corpo de uma função) para adivinhar onde cada definição de função começa na saída detypeset -f
.