Linux 如何设置父进程的工作目录?
正如标题所揭示的,我们正在编写一个Unix风格的shell实用程序U,它应该(在大多数情况下)从bash调用 U如何准确地更改bash的工作目录(或通常的父目录) 另外,shell实用程序chdir成功地实现了完全相同的功能,因此必须有一种编程方式来实现这种效果。除了要求父进程自己更改目录之外,没有“合法”的方式来影响父进程的当前目录 更改bash脚本中目录的chdir不是一个外部实用程序,它是一个内置命令。不要这样做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
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 callcd
”)既可以在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的一部分,使用正常的进程间通信,等等。您不能。就像在现实生活中,你不能改变父母的道路:)
但是,类似的替代方案很少:
/dev/ttyX
,其中X
通常是S0
-S63
,并在那里执行命令当字符串以
\r
结尾时,它可能会模拟按Enter键(回车键)-这取决于您的shell,可以工作或尝试\r\n
。这是一种欺骗,因为命令是在完成进程后执行的,而您是在强迫用户执行某些命令。是否可以以相同的方式调用一个过程,强制Bash检查(可能修改)工作目录?@coderodde查看Bash源代码,很明显,resetpwd(“”)
afterchdir(“…”)
将处理缓存的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 $