AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / ubuntu / 问题 / 1146269
Accepted
jarno
jarno
Asked: 2019-05-27 01:23:56 +0800 CST2019-05-27 01:23:56 +0800 CST 2019-05-27 01:23:56 +0800 CST

如何找到某些 bash 函数的定义位置?

  • 772

Bash shell 中可以使用许多功能。它们的定义可以通过 列出set,但是如何找到在哪些文件中定义了某些用户定义的函数?

bash functions
  • 3 3 个回答
  • 2962 Views

3 个回答

  • Voted
  1. Best Answer
    bashity mcbashface
    2019-05-27T04:53:34+08:002019-05-27T04:53:34+08:00

    打开调试。来自Bash 手册:

    扩展调试

    如果在 shell 调用或 shell 启动文件中设置,安排在 shell 启动之前执行调试器配置文件,与 --debugger选项相同。如果在调用后设置,则启用调试器使用的行为:

    • -F内置选项declare(请参阅Bash Builtins)显示与作为参数提供的每个函数名称相对应的源文件名和行号。

    例子:

    $ bash --debugger
    $ declare -Ff quote
    quote 143 /usr/share/bash-completion/bash_completion
    

    事实上:

    $ nl -ba /usr/share/bash-completion/bash_completion | sed -n 143,150p
       143  quote()
       144  {
       145      local quoted=${1//\'/\'\\\'\'}
       146      printf "'%s'" "$quoted"
       147  }
       148
       149  # @see _quote_readline_by_ref()
       150  quote_readline()
    
    • 36
  2. terdon
    2019-05-27T03:11:26+08:002019-05-27T03:11:26+08:00

    这实际上比最初看起来要复杂得多。您的 shell 读取哪些文件取决于您当前运行的 shell 类型。不管是交互还是非交互,是登录还是非登录shell以及以上的什么组合。要搜索不同 shell 可以读取的所有默认文件,您可以执行以下操作(更改$functionName为您要查找的函数的实际名称):

    grep "$functionName" ~/.bashrc ~/.profile ~/.bash_profile ~/.bash.login \
                         ~/.bash_aliases /etc/bash.bashrc /etc/profile \
                         /etc/profile.d/* /etc/environment 2> /dev/null
    

    如果这不起作用,您可能正在使用.或其别名调用非默认文件source。要查找此类情况,请运行:

    grep -P '(^|\s)(\.|source)\s+' ~/.bashrc ~/.profile ~/.bash_profile \
                                   ~/.bash.login ~/.bash_aliases /etc/bash.bashrc \
                                   /etc/profile /etc/profile.d/* /etc/environment 2> /dev/null
    

    这可能需要一些解释。启用 Perl 兼容正-P则表达式 (PCRE),这让我们可以使用一些更高级的正则表达式语法。具体来说:

    • (^|\s): 匹配行首 ( ^) 或空格 ( \s)。
    • (\.|source)\s+: 匹配文字.字符 ( \.) 或单词source,但前提是它们后跟一个或多个空白字符。

    这是我的系统上给我的东西:

    $ grep -P '(^|\s)(\.|source)\s+' ~/.bashrc ~/.profile ~/.bash_profile \
    >                                ~/.bash.login ~/.bash_aliases /etc/bash.bashrc \
    >                                /etc/profile /etc/profile.d/* /etc/environment 2> /dev/null
    /home/terdon/.bashrc:   . /etc/bashrc
    /home/terdon/.bashrc:   . /etc/bash_completion
    /home/terdon/.bashrc:. $HOME/scripts/git-prompt.sh
    /home/terdon/.bashrc:#  echo -n "$n : "; grep "^CA"  $n |perl -e 'my ($a,$c)=0; while(<>){$c++;next if /cellular_component_unknown/; next if /biological_process/; $a++} print "$a Classes of $c annotated (" . $a*100/$c . ")\n"' 
    /etc/bash.bashrc:[ -r /usr/share/bash-completion/bash_completion   ] && . /usr/share/bash-completion/bash_completion
    /etc/profile:       test -r "$profile" && . "$profile"
    /etc/profile:   . /etc/bash.bashrc
    /etc/profile.d/locale.sh:    . "$XDG_CONFIG_HOME/locale.conf"
    /etc/profile.d/locale.sh:    . "$HOME/.config/locale.conf"
    /etc/profile.d/locale.sh:    . /etc/locale.conf
    /etc/profile.d/Z97-byobu.sh:        . /usr/bin/byobu-launch
    /etc/profile.d/Z97-byobu.sh:        . /usr/bin/byobu-launch
    /etc/profile.d/Z97-byobu.sh:        . /usr/bin/byobu-launch
    /etc/profile.d/Z97-byobu.sh:        . /usr/bin/byobu-launch
    /etc/profile.d/Z97-byobu.sh:        . /usr/bin/byobu-launch
    

    但是,如您所见,这将打印整个匹配的行。我们真正感兴趣的是调用的文件名列表,而不是调用它们的行。你可以用这个更复杂的正则表达式来获得那些:

    grep -hPo '(^|\s)(\.|source)\s+\K\S+' ~/.bashrc ~/.profile ~/.bash_profile \
                                          ~/.bash.login ~/.bash_aliases \
                                          /etc/bash.bashrc /etc/profile \
                                          /etc/profile.d/* /etc/environment 2> /dev/null
    

    该-h标志禁止打印找到匹配项的文件名,grep默认情况下,当被告知搜索多个文件时。意思是“只打印该-o行的匹配部分”。添加到正则表达式的额外内容是:

    • \K: 忽略任何匹配到这一点的东西。-o这是一个 PCRE 技巧,可让您使用复杂的正则表达式来查找匹配项,但在使用 grep 的标志时不包括匹配的部分。

    在我的系统上,上述命令将返回:

    $ grep -hPo '(^|\s)(\.|source)\s+\K\S+' ~/.bashrc ~/.profile ~/.bash_profile \
    >                                       ~/.bash.login ~/.bash_aliases \
    >                                       /etc/bash.bashrc /etc/profile \
    >                                       /etc/profile.d/* /etc/environment 2> /dev/null
    /etc/bashrc
    /etc/bash_completion
    $HOME/scripts/git-prompt.sh
    $a*100/$c
    ")\n"'
    /usr/share/bash-completion/bash_completion
    "$profile"
    /etc/bash.bashrc
    "$XDG_CONFIG_HOME/locale.conf"
    "$HOME/.config/locale.conf"
    /etc/locale.conf
    /usr/bin/byobu-launch
    /usr/bin/byobu-launch
    /usr/bin/byobu-launch
    /usr/bin/byobu-launch
    /usr/bin/byobu-launch
    

    请注意,我碰巧使用了一个不.用于采购的空格,但那是因为我有一个别名调用另一种语言,而不是 bash。这就是在上面的输出中给出奇怪和的原因。但这可以忽略。$a*100/$c")\n"'

    最后,这里是如何将所有这些放在一起并在所有默认文件和您的默认文件来源的所有文件中搜索函数名称:

    grep_function(){
      target="$@"
      files=( ~/.bashrc ~/.profile ~/.bash_profile ~/.bash.login 
             ~/.bash_aliases /etc/bash.bashrc /etc/profile 
             /etc/profile.d/* /etc/environment)
        while IFS= read -r file; do
          files+=( "$file" )
        done < <(grep -hPo '(^|\s)(\.|source)\s+\K\S+'  "${files[@]}" 2>/dev/null)
        for file in "${files[@]}"; do
          ## The tilde of ~/ can break this
          file=$(sed 's|~/|'"$HOME"'/|g' <<<"$file")
          if [[ -e $file ]]; then
            grep -H "$target" -- "$file"
          fi
        done
    }
    

    将这些行添加到您的~/.bashrc,然后您可以运行(我使用fooBar作为示例函数名称):

    grep_function fooBar
    

    例如,如果我的 中有这一行~/.bashrc:

    . ~/a
    

    文件~/a是:

    $ cat ~/a
    fooBar(){
      echo foo
    }
    

    我应该找到它:

    $ grep_function fooBar
    /home/terdon/a:fooBar(){
    
    • 18
  3. dessert
    2019-05-27T02:08:18+08:002019-05-27T02:08:18+08:00

    通常每个用户bash读取的点文件是~/.bashrc. 但是,它可能很好地获取其他文件,例如我喜欢将别名和函数保存在名为~/.bash_aliasesand的单独文件中~/.bash_functions,这使得查找它们变得更加容易。您可以使用以下命令搜索.bashrcforsource命令:

    grep -E '(^\s*|\s)(\.|source)\s' /home/USERNAME/.bashrc
    

    获得用户创建的文件列表后,您可以.bashrc通过一次grep调用搜索它们和用户,例如foo我的设置的功能:

    grep foo /home/USERNAME/.bash{rc,_aliases,_functions}
    
    • 2

相关问题

  • 同时复制到两个位置

  • 如何在 shell 脚本中创建选择菜单?

  • 从 bash 迁移到 zsh [关闭]

  • bashrc 还是 bash_profile?

  • 备份 bash 脚本未压缩其 tarball

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Martin Hope
    Flimm 如何在没有 sudo 的情况下使用 docker? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve