找出 bash 在启动时运行的脚本

sma*_*c89 19 bash profile

启动 bash 终端后,我注意到 PATH 变量包含重复的条目。我的终端启动了一个登录 shell,所以~/.bash_profile是 source ,然后是~/.profileand ~/.bashrc。只有在~/.profile我创建重复的路径条目时。

为了迂腐,这是应该获取的文件的获取顺序:

Sourced /etc/profile
Sourced /etc/bash.bashrc
Sourced .bash_profile
Sourced .profile
Sourced .bashrc
Run Code Online (Sandbox Code Playgroud)

在任何人将此标记为“PATH 变量包含重复项”的副本之前,请继续阅读。

起初,我认为这与~/.profile两次获取有关,所以每当获取时我都会将文件写入日志文件,令人惊讶的是它只记录了一个条目,这告诉我它只获取一次。更令人惊讶的是,当我注释掉 中的条目时~/.profile,这些条目仍然出现在PATH变量中。这使我得出三个结论,其中一个很快就被排除了:

  1. Bash 忽略有效的 bash 注释并仍然执行注释代码
  2. 有一个脚本可以读取~/.profile并忽略任何打印输出的代码(例如日志文件)
  3. 我的另一个副本~/.profile是从别处采购的

第一个,由于一些快速测试,我很快得出结论并非如此。第二个和第三个选项是我需要帮助的地方。

如何收集终端启动时执行的脚本日志?echo在我检查过的文件中使用了它们以了解它们是否来自 bash,但是我需要找到一个结论性的方法来跟踪终端准备好开始输入时的执行情况。

如果以上是不可能的,那么任何人都可以建议我可以在哪里查看正在运行的脚本


以后的参考

这是我现在用于添加到我的路径的脚本:

function add_to_path() {
    for path in ${2//:/ }; do
        if ! [[ "${!1}" =~ "${path%/}" ]]; then # ignore last /
            new_path="$path:${!1#:}"
            export "$1"="${new_path%:}" # remove trailing :
        fi
    done
}
Run Code Online (Sandbox Code Playgroud)

我像这样使用它:

add_to_path 'PATH' "/some/path/bin"
Run Code Online (Sandbox Code Playgroud)

脚本在添加路径之前检查变量中是否已存在该路径。

对于 zsh 用户,您可以使用以下等效项:

# prepends the given path(s) to the supplied PATH variable
# ex. add_to_path 'PATH' "$(go env GOPATH)/bin"
function add_to_path() {
    # (P)1 path is expanded from $1
    # ##: Removes leading :
    local -x pth="${(P)1##:}"
    # (s.:.) splits the given variable at :
    for p in ${(s.:.)2}; do
        # %%/ Remove trailing /
        # :P Behaves similar to realpath(3)
        local p="${${p%%/}:P}"
        if [[ ! "$pth" =~ "$p" ]]; then
            pth="$p:$pth"
        fi
    done
    export "$1"="${pth%%:}"
}
Run Code Online (Sandbox Code Playgroud)

编辑 28/8/2018

我发现我可以用这个脚本做的另一件事是修复路径。所以在我的.bashrc文件的开头,我做这样的事情:

_temp_path="$PATH"
PATH='/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin'
add_to_path 'PATH' "$_temp_path"
unset _temp_path
Run Code Online (Sandbox Code Playgroud)

PATH应该从什么开始取决于你。PATH先检查再决定。

Ale*_*exP 40

如果您的系统有,strace那么您可以列出 shell 打开的文件,例如使用

echo exit | strace bash -li |& grep '^open'
Run Code Online (Sandbox Code Playgroud)

-li表示交互式登录 shell;仅-i用于交互式非登录 shell。)

这将显示 shell 打开或尝试打开的文件列表。在我的系统上,它们如下:

  1. /etc/profile
  2. /etc/profile.d/*(各种脚本/etc/profile.d/
  3. /home/<username>/.bash_profile (这失败了,我没有这样的文件)
  4. /home/<username>/.bash_login (这失败了,我没有这样的文件)
  5. /home/<username>/.profile
  6. /home/<username>/.bashrc
  7. /home/<username>/.bash_history (命令行的历史;这不是脚本)
  8. /usr/share/bash-completion/bash_completion
  9. /etc/bash_completion.d/* (提供自动完成功能的各种脚本)
  10. /etc/inputrc (定义键绑定;这不是脚本)

使用man strace以获取更多信息。

  • 在 macOS 上使用 `sudo bash -c "echo exit|dtruss bash -li|&amp; less|grep '^open'"`。(只需将 `strace` 替换为 [`dtruss`](https://opensourcehacker.com/2011/12/02/osx-strace-equivalent-dtruss-seeing-inside-applications-what-they-do-and-why -他们挂/)) (6认同)
  • @smac89:这对于登录 shell 来说是正常的。当`$0` 的第一个字符是破折号`-` 或使用选项`-l` 调用时,Bash 的行为就像一个登录shell。 (3认同)
  • 为什么不使用老式的方式进行调试,将 `echo PATH=\""$PATH"\"` 放在 `.profile` 和 `.bashrc` 的开头和结尾?为什么你不做每个人都会做的事情并完全设置 PATH,或者如果添加目录,则进行保护: `echo ":$PATH:" | grep -q ":/path/to/dir:" || 导出 PATH="$PATH:/path/to/dir"`? (2认同)
  • 由于 `dtruss` 似乎不再能够在 macOS 上跟踪某些事情(`dtrace:无法执行 /bin/bash:dtrace 无法控制使用受限权利签名的可执行文件`),我不得不求助于以下内容:`/bin/bash -x -l -i -c '退出' 2&gt;&amp;1 | 少` (2认同)

Nao*_*omi 11

重新提出这个问题是因为strace这里太过分了。

执行 bash 并将其从输出中提取出来。-li是交互式登录,-x打印出 bash 内部正在做什么,并-c exit告诉 bash 立即终止。用于sed过滤掉source命令或.别名。

/bin/bash -lixc exit 2>&1 | sed -n 's/^+* \(source\|\.\) //p'
Run Code Online (Sandbox Code Playgroud)