GNU Screen 不会在 10.5.8 上继承我的 PATH

Tim*_*her 11 terminal bash gnu-screen macos

我每天都使用 screen 来满足我的终端需求,我对此非常满意。不过,最近我做了一些更新我的bash配置文件和我注意到,我设置各种PATH元素(PATHMANPATHINFOPATH在2个地方,等)。我将文件修改为它们应该的样子,现在我的所有环境变量都在.bash_profile. 这就是我的问题。

显然,我将它们设置在两个地方的原因是因为屏幕。screen 似乎只执行.bashrc并且似乎没有PATH从我的原始 bash shell 正确继承我的或任何其他环境变量。因为它只执行.bashrc并且我现在只设置我的变量.bash_profile,所以我得到一个不完整的PATH.

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

你可以在我的 GitHub 页面仔细阅读我的配置文件。 这是破坏 screen 的提交提交

编辑:我正在使用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 中,我PATH在 .bash_profile 中所做的更改在进入屏幕时被复制,然后屏幕窗口的连续创建不会复制路径,但会重新获取 .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 ../..'

...

[~]$
Run Code Online (Sandbox Code Playgroud)

第一次调用 screen 的输出:

[~]$ 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 ../..'

...

[~]$
Run Code Online (Sandbox Code Playgroud)

随后调用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 ../..'

...

[~]$
Run Code Online (Sandbox Code Playgroud)

你可以看到

Chr*_*sen 16

屏幕和环境变量

默认情况下,screen将在会话开始时传递给它的外壳程序(和其他进程)它拥有的任何环境变量(即重新连接不会更改为新外壳程序提供的环境变量)。但是因为screen和 shells 的配置文件通常都会改变环境变量,所以有很多地方可以引入意想不到的变化。有一些变量,比如TERM,它几乎总是改变屏幕,但这些通常是屏幕提供的功能所必需的。

假设您的 shell 配置和screen配置都不会修改名为FOOBAR的变量(很可能,总而言之)。如果您使用 启动会话FOOBAR=foo screen,则在该会话中创建的所有 shell 都将具有一个名为FOOBAR且值为 的环境变量foo

对于screen或 shell 可能修改的变量,事情变得更加复杂。

使用屏幕时缺少设置

登录外壳

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

根据屏幕文档

外壳 命令

设置用于创建新 shell 的命令。这会覆盖环境变量 $SHELL 的值。如果你想运行一个 tty-enhancer 来执行 $SHELL 中指定的程序,这很有用。如果命令以“-”字符开头,则外壳将作为登录外壳启动。

屏幕开始壳为“登录”炮弹,开始屏幕screen -s -/bin/bash,或该行添加到您的.screenrc

shell -/bin/bash
Run Code Online (Sandbox Code Playgroud)

调整您碰巧使用的任何外壳的路径。

屏幕配置

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

使用屏幕时重复设置

在 shell 的配置文件中向环境变量(如PATH)添加项是相当常见的,以便更新的值可用于正常的 shell 会话(例如xterm或其他终端窗口、控制台会话等)。如果这些项目被添加到 shell 的 per-shell 配置中(或者,如果您使用上述-/path/to/shell设置,在 shells per-login 配置中),那么由screen启动的 shell可能会有添加项目的多个副本。

避免这种情况的一种策略是将所有添加到诸如PATH之类的变量添加到shell 的每次登录配置中,并避免将-/path/to/shellshell 设置与screen 一起使用

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

另一种策略是始终从配置文件中的固定值开始。当默认值可能显着变化时,这有时会导致在系统之间移动配置文件时出现问题。

诊断

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

检查初始 shell 中的当前值:

echo "$PATH"
Run Code Online (Sandbox Code Playgroud)

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

/bin/bash -c 'echo "$PATH"'
Run Code Online (Sandbox Code Playgroud)

创建“登录”子外壳时,检查外壳如何修改该值:

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

检查屏幕如何修改值:

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
Run Code Online (Sandbox Code Playgroud)


hlo*_*dal 0

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

test -f $HOME/.debug && echo $HOME/.bashrc 1>&2
Run Code Online (Sandbox Code Playgroud)

或类似的。对于特定的调试,您还可以添加诸如

test -f $HOME/.debug && echo PATH now equals $PATH 1>&2
Run Code Online (Sandbox Code Playgroud)

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

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