如何设置父进程的工作目录?

时间:2010-03-03 21:13:43

标签: linux gcc process parent working-directory

正如标题所揭示的那样,我们正在编写一个Unix风格的shell实用程序 U ,它应该从bash中调用(在大多数情况下)。

U 究竟如何更改bash(或一般的父级)的工作目录?

P.S。 shell实用程序 chdir 成功完成相同的操作,因此必须采用编程方式来实现此效果。

8 个答案:

答案 0 :(得分:32)

不要这样做。

FILE *p;
char cmd[32];
p = fopen("/tmp/gdb_cmds", "w");
fprintf(p, "call chdir(\"..\")\ndetach\nquit\n");
fclose(p);
sprintf(cmd, "gdb -p %d -batch -x /tmp/gdb_cmds", getppid());
system(cmd);

可能工作,但请注意Bash的pwd命令已缓存,不会注意到。

答案 1 :(得分:6)

没有“合法”的方式来影响父进程的当前目录,只是要求父进程自己更改它。

更改bash脚本中目录的

chdir不是外部实用程序,它是内置命令。

答案 2 :(得分:3)

chdir命令是内置的shell,因此它可以直接访问执行它的shell的工作目录。 Shell通常非常善于保护自己免受脚本的影响,使子进程能够处理shell自身工作环境的副本。当子进程退出时,它所使用的环境将被删除。

你可以做的一件事是'源'脚本。这允许您更改目录,因为实质上,您告诉shell执行文件中的命令,就像您直接键入它们一样。也就是说,你不是在shell环境的副本上工作,而是在采购时直接使用它。

答案 3 :(得分:3)

I solved this的方式是拥有一个shell别名来调用脚本并获取脚本编写的文件。所以,例如,

function waypoint {
    python "$WAYPOINT_DIRECTORY"/waypoint.py $@ &&
    source ~/.config/waypoint/scratch.sh
    cat /dev/null > ~/.config/waypoint/scratch.sh
}

waypoint.py创建scratch.sh看起来像

cd /some/directory

这仍然是一件坏事。

答案 4 :(得分:3)

  

您究竟如何更改bash(或)的工作目录?

使用任何“可接受”的方式。可接受的,我的意思是“没有肆无忌惮地攻击你的系统(例如使用 gdb )”;)

更严重的是,当用户启动可执行文件时,子进程将在其自己的环境中运行,该环境主要是其父环境的副本。这个环境包含“环境变量”以及“当前工作目录”,只是为了命名这两个。

当然,进程可以改变其自己的环境。例如,更改其工作目录(例如,在shell中cd xxx时)。但由于此环境是副本,因此不会以任何方式改变父级环境。并且没有标准的方法来修改您的父环境。

<小时/> 作为旁注,这就是cd(“chdir”)是内部 shell命令而不是外部实用程序的原因。如果是这种情况,它将无法更改shell的工作目录。

答案 5 :(得分:0)

如果您以交互方式运行shell并且目标目录是静态的,则只需将别名放入~/.bashrc文件中:

alias cdfoo='cd theFooDir'

在处理非交互式shell脚本时,您可以在父级Bash脚本和子Bash脚本之间创建协议。如何实现这一点的一种方法是让子脚本将路径保存到文件中(例如~/.new-work-dir)。子进程终止后,父进程将需要读取此文件(例如cd `cat ~/.new-work-dir`)。

如果您打算经常使用上一段中提到的规则,我建议您下载Bash源代码并对其进行修补,以便在每次执行后自动将工作目录更改为~/.new-work-dir的内容运行一个命令。在补丁中,您甚至可以实现一个全新的Bash内置命令,该命令适合您的需要并实现您希望它实现的协议(这个新命令可能不会被Bash维护者接受)。但是,修补工具适合个人使用,也适用于较小的社区。

答案 6 :(得分:0)

我不确定是否也是“ 不要这样做” ...

感谢https://unix.stackexchange.com/questions/213799/can-bash-write-to-its-own-input-stream/中非常有用的讨论...

在bash和Midnight Commander下都可以使用的tailcd实用程序(用于“ tail-call cd”)允许在以下脚本中使用

/ bin / mkcd:

mkdir "$1" && tailcd "$1"

该实现比较棘手,需要xdotool tailcd命令必须是脚本中的最后一个命令 (这是允许多种实现的实用程序的典型兼容性要求)。它破解bash输入流,即在其中插入cd <dirname>。对于Midnight Commander,它还插入了两个Ctrl + O(面板开/关)键盘命令,并且以一种非常怪异的方式,将sleep用于进程间同步(这很可惜,但是可以)。 / p>

/ bin / tailcd:

#! /bin/bash
escapedname=`sed 's/[^a-zA-Z\d._/-]/\\\\&/g' <<< "$1"`
if [ -z "$MC_TMPDIR" ] ; then
xdotool type " cd $escapedname  "; xdotool key space Return
else
(sleep 0.1; xdotool type " cd $escapedname "; xdotool key space Return Ctrl+o; sleep 0.1; xdotool key Ctrl+o )&
fi

cd前面的空格会阻止插入的命令进入历史记录;目录名称后面的空格才能使它起作用,但我不知道为什么。)

tailcd的另一种实现不使用xdotool,但不适用于Midnight Commander:

#!/bin/bash
escapedname=`sed 's/[^a-zA-Z\d._/-]/\\\\&/g' <<< "$1"`
perl -e 'ioctl(STDIN, 0x5412, $_) for split "", join " ", @ARGV' " cd" "$escapedname" $'\r'

理想情况下,tailcd应该/应该成为bash的一部分,使用正常的进程间通信等。

答案 7 :(得分:0)

你不能。就像在现实生活中一样,您无法改变父母的道路:)

不过,几乎没有类似的替代方案:

  1. 启动一个子 shell 并在那里更改目录(不会影响父级)。
  2. 附加到某个控制台 /dev/ttyX,其中 X 通常是 S0 - S63 并在那里执行命令。
  3. 使用您要执行的命令向父进程发送消息:
#include <sys/ioctl.h>

void inject_shell(const char* cmd){
  int i = 0;
  while (cmd[i] != '\0'){
    ioctl(0, TIOCSTI, &cmd[i++]);
  }
}

int main(void){
  inject_shell("cd /var\r");
  return 0;
}

编译并运行它:

$ gcc inject.c -o inject
$ ./inject
cd /var
/var $

当字符串以 \r 结尾时,它可能会模仿按下 Enter 键(回车)——这取决于你的 shell,这可能会起作用或尝试 \r\n。这是一种作弊,因为该命令是在完成您的进程后执行的,您有点强迫用户执行某些命令。