首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从子进程更改父shell的环境

从子进程更改父shell的环境
EN

Stack Overflow用户
提问于 2014-10-22 15:13:38
回答 2查看 1.5K关注 0票数 2

如果我的程序是用bash以外的语言编写的(例如python),那么如何更改环境变量或其中的当前工作目录,使其在调用的shell中反映出来?

我想用它来编写一个“命令行助手”,它简化了一般操作。例如,智能cd。当我简单地在我的提示符中输入目录的名称时,它应该cd到它。

代码语言:javascript
复制
[~/]$ Downloads
[~/Downloads]$

甚至是

代码语言:javascript
复制
[~/]$ project5
[~/projects/project5]$

然后我找到了handle (这正是我想要做的事情之一),它向我介绍了shopt -s autocd。但是,这仍然不能处理所提供的目录不在./中的情况。

此外,如果我想从python脚本中设置http_proxy变量,甚至更新PATH变量,我的选项是什么?

我了解到,在python脚本中编写自动更新调用shell中的环境变量的神奇命令可能没有明显的方法。我正在寻找一个可行的解决方案,不一定是一个优雅的解决方案。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-10-22 15:16:56

这只能在父shell的参与和协助下才能完成。对于执行此操作的程序的真实示例,您可以查看如何使用ssh-agent

代码语言:javascript
复制
eval "$(ssh-agent -s)"

...reads来自ssh-agent的输出并在当前shell中运行它(-s指定与Bourne兼容的输出,vs csh)。

如果您正在使用Python,请确保使用pipes.quote() (或者,对于Python3.x,shlex.quote())安全地处理输出:

代码语言:javascript
复制
import pipes
dirname='/path/to/directory with spaces'
foo_val='value with * wildcards * that need escaping and \t\t tabs!'
print 'cd %s; export FOO=%s;' % (pipes.quote(dirname), pipes.quote(foo_val))

如果不小心使用...as,可能会导致shell注入攻击。

相反,如果您在bash中将其作为外部脚本编写,请确保使用printf %q进行安全转义(但请注意,它的输出是针对其他bash,而不是针对POSIX遵从性的):

代码语言:javascript
复制
#!/bin/bash
dirname='/path/to/directory with spaces'
foo_val='value with * wildcards * that need escaping and \t\t tabs!'
printf 'cd %q; export FOO=%q;' "$dirname" "$foo_val"

如果像从您的问题中看到的那样,您希望命令看起来是作为本机shell函数编写的,我建议将它包装在一个(这个实践也可以与command_not_found_handle一起使用)中。例如,安装可能涉及在一个人的.bashrc中放置如下内容

代码语言:javascript
复制
my_command() {
  eval "$(command /path/to/my_command.py "$@")"
}

...that用户不需要键入eval

票数 4
EN

Stack Overflow用户

发布于 2014-10-22 18:02:06

本质上,查尔斯达菲击中了钉子的头部,我在这里提出了另一个关于这个问题的旋转。

您所询问的基本上是进程间通信:您有一个进程,它可能是或可能不是shell的子进程(我不认为这很重要),您希望该进程将信息传递给原始shell (顺便说一句,另一个进程),并让它更改其状态。

一种可能是使用信号。例如,在shell中您可以拥有:

代码语言:javascript
复制
trap 'cd /tmp; pwd;' SIGUSR2

现在:

  1. 在shell中键入echo $$,这将给出一个数字,PID。
  2. cd到shell中的一个目录(除/tmp以外的任何目录)
  3. 转到另一个shell (在另一个窗口或其他什么地方),键入:杀死SIGUSR2 PID
  4. 您将发现您在原始shell中的/tmp中。

这就是沟通渠道的一个例子。当然,魔鬼在细节上。您的问题有两部分:如何让shell与您的程序进行通信(如果这对您有效,command_not_found_handle会很好地做到这一点),以及如何让您的程序与shell通信。下面,我将讨论后一个问题:

例如,您可以在原始shell中有一个trap语句:

代码语言:javascript
复制
trap 'eval $(/path/to/my/fancy/command $(pwd) $$)' SIGUSR2

...your fancy命令将被赋予原始shell的当前工作目录作为第一个参数,以及shell的进程id (因此它知道该向谁发送信号),并且它可以对其进行操作。如果您的命令将一个可执行的shell命令字符串发送到eval命令,那么它将在原始shell的环境中执行。

例如:

代码语言:javascript
复制
trap 'eval $(/tmp/doit $$ $(pwd)); pwd;' SIGUSR2

/tmp/doit是一个奇特的命令。它可以是任何可执行类型的Python、C、Perl等),关键是它释放出一个shell可以计算的字符串。在/tmp/doit中,我提供了一个bash脚本:

代码语言:javascript
复制
#!/bin/bash
echo "echo PID: $1 original directory: $2; cd /tmp"

(我确保文件是可执行的: chmod 755 /tmp/doit)。现在,如果我键入:

代码语言:javascript
复制
cd; echo $$

然后,在另一个shell中,根据上面的echo获取数字输出("NNNNN"),然后执行:

代码语言:javascript
复制
kill -s SIGUSR2 NNNNN

...then突然间,我会在原来的shell中看到这样的东西:

代码语言:javascript
复制
PID: NNNNN original directory: /home/myhomepath
/tmp

如果我在原来的shell中输入"pwd“,我会看到我在/tmp中。

想让command_not_found_handle在当前的shell环境中做些什么的人可以使用信号来达到他想要的效果。在这里,我是手动运行杀死的,但是没有理由shell函数不能这样做。

在前端执行花哨的工作,即重新解释或预先解释用户对shell的输入,可能需要用户运行一个可能非常复杂的前端程序,这取决于您想要做什么。老派的“期待”计划是这样的理想方案,但现在没有太多的年轻人开始使用TCL :-)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26510898

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档