Bash – How to print out the complete function declaration of any function which has a specific string inside it

bashfunctionshell-scripttext processing

I have lots of functions in my bashrc, but for newly created ones I often forget the name of the function.

So for example, when I have defined this function in my .bashrc:

function gitignore-unstaged
{
    ### Description:
    # creates a gitignore file with every file currently not staged/commited.
    # (except the gitingore file itself)
    ### Args: -

    git ls-files --others | grep --invert-match '.gitignore' > ./.gitignore

}

And I would like to have another function which prints out the definition of the function like:

$ grepfunctions "gitignore"
function gitignore-unstaged
{
    ### Description:
    # creates a gitignore file with every file currently not staged/commited.
    # (except the gitingore file itself)
    ### Args: -

    git ls-files --others | grep --invert-match '.gitignore' > ./.gitignore
}

But instead of matching for "gitignore" I want it to match every string between funtction and }, so $ grepfunctions "###" and $ grepfunctions "creates" should output the exact same thing. That's also the reason, why declare -f and such don't solve the problem.

What I have tried

  • I can't use grep
  • I know, that sed -n -e '/gitignore-unstaged/,/^}/p' ~/.bashrc prints out what i want – but sed -n -e '/creates/,/^}/p' ~/.bashrc not. Instead, I receive:

        # creates a gitignore file with every file currently not staged/commited.
        # (except the gitingore file itself)
        ### Args: -
    
        git ls-files --others | grep --invert-match '.gitignore' > ./.gitignore
    }
    

    The function name and the first { are cut out, which is not what I want.

How can I print out the complete function declaration of any function which has a specific string inside it? Of course, other tools than sed are also allowed.

Best Answer

Note that with zsh, you can do:

 printf '%s() {\n%s\n}\n\n' ${(kv)functions[(R)*gitignore*]}

To retrieve the information from the currently defined functions (that doesn't include the comments obviously).

Now, if you want to extract the information from the source file, then you can't do reliably unless you implement a full shell parser.

If you can make some assumption on how your functions are declared, like for instance if you always use that ksh-style function definition, with function and } at the start of the line, you could do:

perl -l -0777 -ne 'for (/^function .*?^\}$/gms) {
  print if /gitignore/}' ~/.bashrc

or to only look in the function body:

perl -l -0777 -ne 'for (/^function .*?^\}$/gms) {
  print if /\{.*gitignore/s}' ~/.bashrc
Related Question