Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 如何设置父进程的工作目录?_Linux_Gcc_Process_Parent_Working Directory - Fatal编程技术网

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

Linux 如何设置父进程的工作目录?,linux,gcc,process,parent,working-directory,Linux,Gcc,Process,Parent,Working Directory,正如标题所揭示的,我们正在编写一个Unix风格的shell实用程序U,它应该(在大多数情况下)从bash调用 U如何准确地更改bash的工作目录(或通常的父目录) 另外,shell实用程序chdir成功地实现了完全相同的功能,因此必须有一种编程方式来实现这种效果。除了要求父进程自己更改目录之外,没有“合法”的方式来影响父进程的当前目录 更改bash脚本中目录的chdir不是一个外部实用程序,它是一个内置命令。不要这样做 FILE *p; char cmd[32]; p = fopen("/tmp

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

U如何准确地更改bash的工作目录(或通常的父目录)

另外,shell实用程序chdir成功地实现了完全相同的功能,因此必须有一种编程方式来实现这种效果。

除了要求父进程自己更改目录之外,没有“合法”的方式来影响父进程的当前目录

更改bash脚本中目录的chdir不是一个外部实用程序,它是一个内置命令。

不要这样做

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
命令是缓存的,不会注意到。

chdir命令是一个内置的shell,因此它可以直接访问执行它的shell的工作目录。shell通常非常擅长保护自己不受脚本的影响,为子进程提供shell自己工作环境的副本。当子进程退出时,它使用的环境将被删除


您可以做的一件事是“源”脚本。这允许您更改目录,因为本质上,您是在告诉shell从文件中执行命令,就像您直接键入命令一样。也就是说,在寻源时,您不是从shell环境的副本工作,而是直接在其上工作。

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

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

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

方法是使用一个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
这仍然是一件坏事

如何确切地更改bash的工作目录(或一般的父目录)

使用任何“可接受”的方式都是不可能的。我所说的“可接受”是指“没有对您的系统进行过分的黑客攻击(例如使用gdb)”;)

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

当然,一个进程可以改变它自己的环境。例如,更改其工作目录(如在shell中
cdxxx
时)。但由于此环境是一个副本,因此不会以任何方式改变父环境。并且没有标准的方法来修改您的父环境。
作为旁注,这就是为什么
cd
(“chdir”)是一个内部shell命令,而不是一个外部实用程序。如果是这样的话,它将无法更改shell的工作目录。

我不确定这是否也是一个“不要这样做”的问题

感谢…中非常有用的讨论

tailcd
实用程序(用于“tail call
cd
”)既可以在bash中工作,也可以在Midnight Commander下工作,允许在脚本中使用,如

/bin/mkcd:

mkdir "$1" && tailcd "$1"
实现起来很棘手,需要
xdool
脚本中的最后一个命令必须是
tailcd
(这是允许多个实现的实用程序的典型兼容性要求)。它攻击bash输入流,即在其中插入
cd
。在Midnight Commander中,它还插入了两个Ctrl+O(面板开/关)键盘命令,并以一种非常粗俗的方式使用睡眠进行进程间同步(这很遗憾,但它可以工作)

/箱/尾CD:

#! /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

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

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

但是,类似的替代方案很少:

  • 启动子shell并在那里更改目录(不会影响父目录)
  • 连接到某个控制台
    /dev/ttyX
    ,其中
    X
    通常是
    S0
    -
    S63
    ,并在那里执行命令
  • 使用要执行的命令向父进程发送消息:

  • 当字符串以
    \r
    结尾时,它可能会模拟按Enter键(回车键)-这取决于您的shell,可以工作或尝试
    \r\n
    。这是一种欺骗,因为命令是在完成进程后执行的,而您是在强迫用户执行某些命令。

    是否可以以相同的方式调用一个过程,强制Bash检查(可能修改)工作目录?@coderodde查看Bash源代码,很明显,
    resetpwd(“”)
    after
    chdir(“…”)
    将处理缓存的pwd。但是您没有读到“不要这样做”吗
    #!/bin/bash
    escapedname=`sed 's/[^a-zA-Z\d._/-]/\\\\&/g' <<< "$1"`
    perl -e 'ioctl(STDIN, 0x5412, $_) for split "", join " ", @ARGV' " cd" "$escapedname" $'\r'
    
    #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 $