如何让终端窗口在打开脚本后继续存在?(不只是“保持窗口打开”或启动新 shell)

如何让终端窗口在打开脚本后继续存在?(不只是“保持窗口打开”或启动新 shell)

我并不特别要求使用 shell 脚本来实现此目的,但我的要求如下:

  • 我可以双击桌面上的图标。(这是为了选择一个可选的,替代的启动终端窗口的方式;所以我不能只需编辑一个.bashrc.profile等等)
  • 这将打开一个终端窗口并运行一些命令,包括另一个脚本。(根据文档,这一个必须来自sourceBash。)
  • 命令运行后,窗口保持打开状态无限期,可用于输入更多 shell 命令. (这意味着任何基于read等的东西xterm -keep都是不是一个办法。)
  • 已运行的命令影响 shell 的状态(这就是我在这里要问问题的原因。)

具体用例是,我想要打开一个窗口,从一个特定的目录启动(在我的情况下,是桌面上的一个文件夹,其中包含我正在处理的 Python 项目的子目录),并激活一个 Python 虚拟环境(在我的情况下,是SANDBOX位于该目录中的一个名为“scratch”的常见 venv)。

经过大量研究,我最终得出了以下结论:

#!/bin/bash
cd ~/Desktop/dev
source SANDBOX/bin/activate
exec $SHELL

这是几乎对。如果真的需要的话,我可以忍受它,这已经足够好了,但我真的被它的缺点困扰了。在我的测试中,窗口保持打开状态并且可用;密码设置正确;并且脚本正确修改了VIRTUALENVPATH环境变量。但是,PS1没有设置,因此提示符没有被修改,并且命令deactivate没有像通常那样可用。

我怎样才能让它完全透明?

答案1

信用

Kamil 的答案对我来说很有效,但事实证明我还有一些额外的小要求,直到我看到答案我才意识到。凭借这种新的理解,我设法以完全不同的方式解决了这个问题。

讨论

就我而言,我真的不想修改自定义脚本,因为它是由 Python 生成的。(在更一般的情况下,我还希望能够在不重新加载 .bashrc 的情况下运行脚本。)我也不想编写单独的自定义 rcfile,因为它感觉不可扩展;现在我正在制作每次我需要这种包装器时,我都会创建一个特殊的文件(并且我还希望它能用于其他一些事情)。

这些问题似乎是由于启动新 shell 造成的,即使使用exec而不是命令。虽然它确实正确地管理了窗口的生命周期,

  • .bashrc 再次运行,覆盖设置PS1

  • 函数定义不会被导出,所以新的 shell 根本没有它。

第一个问题实际上不能通过使用 来解决exec bash --norc,因为我希望从两个地方修改PS1—— 只是顺序不同。第二个问题根本没有通过这种方式解决。

使原始方法奏效的诀窍是activate脚本必须在最后的shell 创建(无论有多少个)。该 shell 需要通过某种方法运行 .bashrc,然后运行原始脚本内容。但是...如果我们不打算修改原始脚本(首先获取 .bashrc;不​​打算制作单独的脚本包装器(按顺序运行两者);不打算按顺序运行bash -c两者(这行不通;我们需要-c按顺序安排,但这样我们就得不到持久终端)——我们该怎么办?

我的解决方案

我想到的是:反转逻辑,并.bashrc(有条件地)获取新脚本。由于我们无法向其传递命令行参数(bash如果没有 ,它们将转到调用-c,而有了 ,-c我们又得不到持久终端),我们通过设置环境变量来传递必要的信息。为此,我们需要一个外部的包装子 shell。

我在末尾添加了以下内容.bashrc

if [ -f "$MORE_STARTUP" ]; then
    . $MORE_STARTUP
elif [ -n "$MORE_STARTUP" ]; then
    echo "Warning! Could not run ${MORE_STARTUP}"
fi

现在MORE_STARTUP,如果设置并找到环境变量,则该变量指定一个脚本,其中包含要采取的其他设置操作。它通过普通脚本进行设置:

#!/bin/bash
cd /path/to/start/dir
export MORE_STARTUP=path/to/script
exec bash

但是,这仍然保留了 Cinnamon 关于执行文本文件的警告,并且“在终端中运行”选项对于使其工作是必需的。这仍然有点尴尬。相反,按照原来的建议,我制作了一个形状如下的启动器:

[Desktop Entry]
Exec=/bin/bash -c "export MORE_STARTUP=\"path/to/script\" && /bin/bash"
Icon=some-icon
Name=custom terminal
Path=/path/to/start/dir
Terminal=true
Type=Application

我发现 shell 扩展在选项中不起作用Path。将 a 添加cd到命令序列中也应该有效,但使用Path似乎更简洁。这里不需要转义引号,但如果路径中有空格等,则需要。

现在每个原始脚本只有一个包装器,双击即可完成我想要的所有操作。我甚至开始编写一个脚本来生成此类启动器(添加一个函数被.bashrc证明很笨重,所以我将改用 Python)。

答案2

解决方案

创建快捷方式(a.desktop文件或其他任何可以在终端仿真器中运行命令的程序。命令应该是:

/bin/bash --rcfile /path/to/rcfile

rcfile自定义文件在哪里来源:bash代替~/.bashrc*. 在文件中执行您想要的源,调用cd或任何其他操作。您可能无论如何都想要执行源~/.bashrc,因此请在自定义文件中明确执行。不要再生出另一个bash

*有些发行版之前会发布bash源代码/etc/bash.bashrc~/.bashrc,然后--rcfile将它们替换为单个自定义文件。 如果需要,调整答案的其余部分。


概念验证

这是我的例子customshell.desktop

[Desktop Entry]
Comment=
Exec=/bin/bash --rcfile ~/.myspecialbashrc
Icon=utilities-terminal
Name=My custom shell
Path=
StartupNotify=true
Terminal=true
TerminalOptions=
Type=Application

并且~/.myspecialbashrc是:

if [ -f ~/.bashrc ]; then
  . ~/.bashrc
fi
cd ~/Desktop/dev
. SANDBOX/bin/activate

我使用一个设置 shell 变量和一些 shell 选项的简单activate文件进行了测试。它成功了,我得到的交互式 shell 的配置与计划完全一致。


简化

最终设置源~/Desktop/dev/SANDBOX/bin/activate。如果您不介意在activate文件中添加其他内容,那么您不需要任何额外的 rcfile(如上所示~/.myspecialbashrc)。桌面文件将如下所示:

[Desktop Entry]
Comment=
Exec=/bin/bash --rcfile SANDBOX/bin/activate
Icon=utilities-terminal
Name=My custom shell
Path=~/Desktop/dev
StartupNotify=true
Terminal=true
TerminalOptions=
Type=Application

NotePath=~/Desktop/dev负责在bash启动之前输入正确的目录,因此我们稍后不需要cd(即在activate文件中)。不过,如果您想要源代码,~/.bashrc则需要从activate文件内部获取源代码。

如果您不能或不想更改文件,activate请坚持使用第一个解决方案(使用~/.myspecialbashrc; notePath=~/Desktop/dev而不是仍然是一个选项)。如果您可以通过在命令行中提供多个文件( )来按顺序cd生成源文件,那就太好了;但在我的测试中,这不起作用,只有最后一个文件有效。bash--rcfilebash --rcfile … --rcfile …--rcfile

相关内容