屏幕和环境变量

屏幕和环境变量

我每天都使用 screen 来满足我的终端需求,我对它很满意。不过,最近我对我的 bash 配置文件进行了一些更新,我注意到我在 2 个地方设置了各种PATH元素(PATHMANPATHINFOPATH等)。我修改了文件,使之符合要求,现在我的所有环境变量都在 中设置了一次.bash_profile。这就是我的问题所在。

显然,我把它们设置在两个地方的原因是因为屏幕。屏幕似乎只执行.bashrc并且确实不是似乎PATH正确地从我的原始 bash shell 继承了我的或任何其他环境变量。由于它仅执行.bashrc并且我现在仅在中设置我的变量.bash_profile,因此我得到了不完整的PATH

那么,我的问题是如何将我的环境变量放入屏幕而不重复。阅读文档Bash似乎表明它可以screen 用于登录的 shell 类型,即非登录交互式 shell但我无法弄清楚如何强制屏幕使用特定类型的 shell,而只能使用通过的 shell -s /bin/bash

你可以仔细阅读我的配置文件我的 GitHub 页面这是打破屏幕的提交提交

编辑:我正在使用Screen version 4.00.03 (FAU) 23-Oct-06并且倾向于通过以下方式调用它screen -h 50000

编辑:我现在已经能够在 Cygwin ( CYGWIN_NT-5.1 1.7.1(0.218/5/3) i686, Screen version 4.00.03 (FAU) 23-Oct-06) 上对此进行测试,并且它表现出与我的 Mac 不同的行为。

我现在发现的具体行为是,在 Cygwin 中,我在 .bash_profile 中所做的更改PATH在进入屏幕时会重复,然后连续创建屏幕窗口不会重复路径,但会重新提供 .bash_profile。

为了说明我所谈论的行为:

来自新终端的输出:

...

PATH: /home/tvishe01/bin/emacs/bin:/home/tvishe01/bin:/usr/local/bin:/usr/bin:/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/WINDOWS/System32/Wbem:/cygdrive/c/Program Files/ATI Technologies/ATI.ACE/Core-Static:/groovy-1.6.1/bin:/usr/lib/lapack

MANPATH: /home/tvishe01/share/man:/usr/local/man:/usr/share/man:/usr/man::/usr/ssl/man

Aliases:
alias ..='cd ..'
alias ...='cd ../..'

...

[~]$

第一次调用屏幕的输出:

[~]$ screen -h 50000 -s -/bin/bash

...

PATH: /home/tvishe01/bin/emacs/bin:/home/tvishe01/bin:/usr/local/bin:/usr/bin:/bin:/home/tvishe01/bin/emacs/bin:/home/tvishe01/bin:/usr/local/bin:/usr/bin:/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/WINDOWS/System32/Wbem:/cygdrive/c/Program Files/ATI Technologies/ATI.ACE/Core-Static:/groovy-1.6.1/bin:/usr/lib/lapack

MANPATH: /home/tvishe01/share/man:/usr/local/man:/usr/share/man:/usr/man:/home/tvishe01/share/man:/usr/local/man:/usr/share/man:/usr/man::/usr/ssl/man:/usr/ssl/man

Aliases:
alias ..='cd ..'
alias ...='cd ../..'

...

[~]$

后续调用C-a c

...

PATH: /home/tvishe01/bin/emacs/bin:/home/tvishe01/bin:/usr/local/bin:/usr/bin:/bin:/home/tvishe01/bin/emacs/bin:/home/tvishe01/bin:/usr/local/bin:/usr/bin:/bin:/cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:/cygdrive/c/WINDOWS/System32/Wbem:/cygdrive/c/Program Files/ATI Technologies/ATI.ACE/Core-Static:/groovy-1.6.1/bin:/usr/lib/lapack

MANPATH: /home/tvishe01/share/man:/usr/local/man:/usr/share/man:/usr/man:/home/tvishe01/share/man:/usr/local/man:/usr/share/man:/usr/man::/usr/ssl/man:/usr/ssl/man

Aliases:
alias ..='cd ..'
alias ...='cd ../..'

...

[~]$

您可以看到

答案1

屏幕和环境变量

默认情况下,屏幕将会话启动时所具有的任何环境变量传递给其 shell(和其他进程)(即重新连接不会改变分配给新 shell 的环境变量)。但由于两者屏幕并且 shell 的配置文件通常会更改环境变量,因此有很多地方可能会引入意外更改。有几个变量,例如学期, 那屏幕它几乎总是会改变,但这些通常是功能所必需的屏幕提供。

假设你的 shell 配置和屏幕的配置将修改名为酒吧(总体来说,很有可能)。如果您使用 启动会话FOOBAR=foo screen,则在该会话中创建的所有 shell 都将具有一个名为酒吧其值为foo

对于以下变量,事情变得更加复杂:屏幕或者你的 shell 可能会修改。

使用时缺少设置屏幕

登录 Shell

如果你发现由以下程序启动的 shell 中缺少某些设置:屏幕,可能是因为您的 shell 仅配置为更新“登录”shell 的设置。大多数 shell 都理解一个特殊约定(在 C: 中**argv == '-'),即屏幕即可配置使用。

根据屏幕文档

命令

设置用于创建新 shell 的命令。这将覆盖环境变量 $SHELL 的值。如果您想要运行期望执行 $SHELL 中指定的程序的 tty-enhancer,这将非常有用。如果命令以“-”字符开头,则 shell 将作为登录 shell 启动。

具有屏幕将 shell 启动为“登录”shell,启动屏幕或者screen -s -/bin/bash将这一行添加到您的.screenrc

shell -/bin/bash

调整您正在使用的 shell 的路径。

屏幕配置

丢失或重置环境变量也可能是setenv由于unsetenv屏幕配置文件。您必须检查.screenrc在你的主目录中,以及你编译的任何文件中屏幕用作“系统 screenrc”(您可以尝试使用类似命令strings "$(which screen)" | fgrep -i screenrc来查找在编译时配置的路径名——通常/etc/screenrc对于系统安装的屏幕;附加组件安装可能会使用其他路径名)。您可以使用SCREENRC=/dev/null SYSSCREENRC=/dev/null screen暂时避免这些设置文件,但有一个编译时选项会阻止有效使用系统屏幕显示(大概是为了让系统管理员可以强制进行一些初始配置)。

使用时重复设置屏幕

向环境变量中添加项是很常见的,例如小路在 shell 的配置文件中,以便更新的值可用于正常的 shell 会话(例如终端或其他终端窗口、控制台会话等)。如果在 shell 的每个 shell 配置中添加了此类项目(或者,如果您使用-/path/to/shell上述设置,则在 shell 的每个登录配置中添加了此类项目),则由屏幕可能会有添加项目的多个副本。

避免这种情况的一个策略是将所有添加的内容放入变量中,例如小路在 shell 的每次登录配置中,避免使用-/path/to/shellshell 设置屏幕

另一种策略是仅有条件地将新项添加到变量中。根据 shell 的不同,执行此操作的代码可能有点复杂,但通常可以将其封装在 shell 函数中以方便使用。

另一个策略是始终在配置文件中以固定值开始。当将配置文件从一个系统移动到另一个系统时,默认值可能会有很大差异,这有时会造成问题。

诊断

如果您不能直接发现特定修改发生的位置,您可以尝试以下方法来追踪发生更改的位置。

检查初始 shell 中的当前值:

echo "$PATH"

检查创建子 shell 时 shell 本身如何修改该值:

/bin/bash -c 'echo "$PATH"'

检查在创建“登录”子 shell 时 shell 如何修改该值:

perl -e '$s=shift;exec {$s} "-$s", @ARGV or die "unable to start shell"' /bin/bash
echo "$PATH"
exit

检查如何屏幕修改值:

printf '#!/bin/sh\nl=/tmp/echo-var.log;rm -f "$l"; echo $PATH >"$l"' >/tmp/echo-var &&
chmod a+x /tmp/echo-var &&
screen -s /tmp/echo-var &&
cat /tmp/echo-var.log

答案2

上次我看到类似的问题时,我通过使用screen -l启动屏幕解决了它。

您可以-l在调用时使用该选项screen(转登录模式defloginon;也由 中的和login命令控制.screenrc)来设置屏幕是否应默认记录窗口(添加/删除 /etc/utmp 条目)。

默认情况下登录模式处于开启状态,但可以在编译时更改。如果 screen 未使用 utmp 支持进行编译,则这些命令不可用。

我似乎不需要-lDebian Lenny 默认屏幕 (v4.0.3) 中的模式;默认情况下它似乎处于启用状态。我的~/.profile~/.bashrc正在正确读取。您如何调用screen?您使用的是哪个版本?

答案3

问题在于 Leopard 上的 launchd 行为。请参阅此 MacPorts 错误报告,了解 Leopard 上的屏幕错误,了解为什么除非您能以某种方式反向移植 Snow Leopard 的 launchd,否则该问题永远无法修复。

https://trac.macports.org/ticket/18235#comment:26

答案4

每当我遇到类似的问题时,我都会创建一个文件,$HOME/.debug并且在登录/shell 调用期间获取/执行的所有文件中(例如~/.bashrc,,,,等),我将其作为第一行~/.bash_profile~/.profile/etc/bashrc

test -f $HOME/.debug && echo $HOME/.bashrc 1>&2

或类似内容。对于特定调试,您还可以添加类似

test -f $HOME/.debug && echo PATH now equals $PATH 1>&2

这样,您就可以 100% 绝对确定哪些文件被使用或未被使用。

重定向到 stderr 很重要,在很多情况下您都不希望某些东西弄乱 stdout。

相关内容