如何设置父进程的工作目录?
正如标题所示,我们正在编写一个 Unix 风格的 shell 实用程序 U,它应该从 bash 调用(在大多数情况下)。
U 究竟如何更改 bash 的工作目录(或一般的父目录)?
PS shell 实用程序 chdir 成功地完成了完全相同的操作,因此必须有一种编程方式来实现该效果。
As the title reveals it, we are writing a Unix-style shell utility U that is supposed to be invoked (in most cases) from bash.
How exactly could U change the working directory of bash (or parent in general)?
P.S. The shell utility chdir succeeds in doing exactly the same, thus there must be a programmatic way of achieving the effect.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
不要这样做。
它可能会工作,但请注意,Bash 的
pwd
命令已缓存并且不会注意到。Don't do this.
It will probably work, though note that Bash's
pwd
command is cached and won't notice.除了要求父进程自行更改之外,没有“合法”方法可以影响父进程的当前目录。
更改 bash 脚本中的目录的 chdir 不是外部实用程序,而是内置命令。
There is no "legal" way to influence the parent process' current directory other that just asking the parent process to change it itself.
chdir
which changes the directory in bash scripts is not an external utility, it's a builtin command.chdir 命令是 shell 内置命令,因此它可以直接访问执行它的 shell 的工作目录。 shell 通常非常擅长保护自己免受脚本的影响,为子进程提供 shell 自身工作环境的副本。当子进程退出时,它使用的环境将被删除。
您可以做的一件事就是“获取”脚本。这允许您更改目录,因为本质上,您是在告诉 shell 执行文件中的命令,就像您直接键入它们一样。也就是说,您不是在 shell 环境的副本中工作,而是在采购时直接在其上工作。
The chdir command is a shell built-in, so it has direct access to the working directory of the shell that executes it. Shells are usually pretty good at protecting themselves from the effects of scripts, giving the child process a copy of the shell's own working environment. When the child process exits, the environment it used is deleted.
One thing you can do is 'source' a script. This lets you change the directory because in essence, you are telling the shell to execute the commands from the file as though you had typed them in directly. I.e., you're not working from a copy of the shell's environment, you are working directly on it, when sourcing.
我解决这个问题的方法是使用一个 shell 别名来调用脚本并获取脚本编写的文件。例如,
waypoint.py
创建scratch.sh
看起来这仍然是一件坏事。
The way I solved this is to have a shell alias that calls the script and source a file that the script wrote. So, for instance,
and
waypoint.py
createsscratch.sh
to look likeThis is still a Bad Thing.
使用任何“可接受”的方式不可能。我所说的可接受,是指“无需粗暴地攻击您的系统(例如使用gdb)”;)
更严重的是,当用户启动可执行文件时,子进程将在其自己的运行 em> 环境,主要是其父环境的副本。该环境包含“环境变量”以及“当前工作目录”,仅举两个例子。
当然,进程可以改变它自己的环境。例如,更改其工作目录(例如在 shell 中
cd xxx
时)。但由于这个环境是一个副本,因此不会以任何方式改变父环境。并且没有标准的方法来修改您的父环境。As a side note, this is why
cd
("chdir") is an internal shell command, and not an external utility. If that was the case, it wouldn’t be able to change the shell's working directory.It is not possible by using any "acceptable" way. By acceptable, I mean "without outrageously hacking your system (using gdb for example)" ;)
More seriously, when the user launch an executable, the child process will run in its own environment, which is mostly a copy of its parent environment. This environment contains "environment variables" as well as the "current working directory", just to name those two.
Of course, a process can alter its own environment. For example to change its working directory (like when you
cd xxx
in you shell). But since this environment is a copy, that does not alter the parent's environment in any way. And there is no standard way to modify your parent environment.As a side note, this is why
cd
("chdir") is an internal shell command, and not an external utility. If that was the case, it wouldn’t be able to change the shell's working directory.你不能。就像在现实生活中一样,您无法更改父母的路径:)
不过,有一些类似的替代方案:
/dev/ttyX
,其中X
通常是S0
-S63
并在那里执行命令。编译并运行它:
当字符串以
\r
终止时,它可能会模仿按 Enter 键(回车) - 根据您的 shell,这可能有效或尝试\r\n
。这是一种作弊行为,因为该命令是在完成进程后执行的,并且您有点强迫用户执行某些命令。You can't. Like in real life you can't change the path of your parents :)
Though, there are few similar alternatives:
/dev/ttyX
whereX
is usuallyS0
-S63
and execute commands there.compile and run it:
When the string is terminated with
\r
it might imitate hitting the Enter key (carriage return) - depending on your shell this could work or try\r\n
. This is a cheating since the command is executed after finishing your process and you're kind of forcing the user to execute some command.如果您以交互方式运行 shell 并且目标目录是静态的,您可以简单地将别名放入
~/.bashrc
文件中:在处理非交互式 shell 脚本时,您可以创建一个协议父 Bash 脚本和子 Bash 脚本之间。实现此目的的一种方法是让子脚本将路径保存到文件中(例如
~/.new-work-dir
)。子进程终止后,父进程需要读取此文件(例如 cd `cat ~/.new-work-dir` )。如果你打算经常使用上一段提到的规则,我建议你下载 Bash 源代码并修补它,以便它自动将工作目录更改为
~/.new-work-dir< 的内容/code> 每次运行命令后。在补丁中,您甚至可以实现一个全新的 Bash 内置命令,它适合您的需求并实现您希望它实现的协议(这个新命令可能不会被 Bash 维护者接受)。但是,修补适用于个人使用和较小的社区。
In case you are running the shell interactively and the target directory is static, you can simply put an alias into your
~/.bashrc
file:When dealing with non-interactive shell scripts, you can create a protocol between the parental Bash script and the child Bash script. One method of how to implement this is to let the child script save the path into a file (such as
~/.new-work-dir
). After the child process terminates, the parental process will need to read this file (such ascd `cat ~/.new-work-dir`
).If you plan to use the rule mentioned in the previous paragraph very often, I would suggest you download Bash source code and patch it so that it automatically changes the working directory to the contents of
~/.new-work-dir
after each time it runs a command. In the patch, you could even implement an entirely new Bash built-in command which suits your needs and implements the protocol you want it to implement (this new command probably won't be accepted by the Bash maintainers). But, patching works for personal use and for use in a smaller community.我不确定这是否也是“不要这样做”...
感谢 https://unix.stackexchange.com/questions/213799/can-bash-write-to-its-own-input-stream/ ...
tailcd
实用程序(用于“tail-callcd
”)可在 bash 和 Midnight Commander 下运行,允许在/bin 等脚本中使用/mkcd:
实现很棘手,需要插入其中。就 Midnight Commander 而言,它还插入了两个 Ctrl+O(面板开/关)键盘命令,并以一种非常黑客的方式使用睡眠来进行进程间同步(这很遗憾,但它确实有效)。
xdotool
。tailcd
命令必须是脚本中的最后一个命令(这是允许多种实现的实用程序的典型兼容性要求)。它侵入 bash 输入流,即将 cd/bin/tailcd:(
cd
之前的空格阻止插入的命令进入历史记录;目录名后面的空格需要它才能工作,但我不知道为什么。)另一个实现
tailcd
不使用xdotool
,但它不适用于 Midnight Commander:理想情况下,
tailcd
将/应该是 bash 的一部分,使用普通进程间通信等I am not sure if it is a "don't do this" too...
Thanks to the extremely useful discussion in https://unix.stackexchange.com/questions/213799/can-bash-write-to-its-own-input-stream/ ...
The
tailcd
utility (for "tail-callcd
") that works both in bash and under the Midnight Commander allows usage in scripts like/bin/mkcd:
The implementation is tricky and it requires
xdotool
. Thetailcd
command must be the last command in the script (this is a typical compatibility requirement for utilities that allow multiple implementations). It hacks the bash input stream, namely, insertscd <dirname>
into it. In the case of Midnight Commander, it in addition inserts two Ctrl+O (panels on/off) keyboard commands and, in a very hackish manner, uses sleep for inter-process synchronization (which is a shame, but it works)./bin/tailcd:
(The space before
cd
prevents the inserted command from going to the history; the spaces after the directory name are required for it to work but I do not know why.)Another implementation of
tailcd
does not usexdotool
, but it does not work with Midnight Commander:Ideally,
tailcd
would/should be a part of bash, use normal inter-process communication, etc.