Как мне установить рабочий каталог родительского процесса? - PullRequest
23 голосов
/ 04 марта 2010

Как видно из названия, мы пишем утилиту оболочки в стиле Unix U , которая должна вызываться (в большинстве случаев) из bash.

Как именно U может изменить рабочий каталог bash (или вообще родительский)?

P.S. Утилита оболочки chdir делает то же самое, поэтому должен быть программный способ достижения эффекта.

Ответы [ 7 ]

32 голосов
/ 04 марта 2010

Не делай этого.

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 кэшируется и не заметит.

6 голосов
/ 04 марта 2010

Не существует "легального" способа повлиять на текущий каталог родительского процесса, кроме как просто попросить родительский процесс изменить его сам.

chdir, который изменяет каталог в скриптах bash, это не внешняя утилита, а встроенная команда.

4 голосов
/ 04 марта 2010

Команда chdir является встроенной в оболочку, поэтому она имеет прямой доступ к рабочему каталогу оболочки, которая ее выполняет.Оболочки обычно довольно хорошо защищают себя от воздействия сценариев, предоставляя дочернему процессу копию собственной рабочей среды оболочки.Когда дочерний процесс завершается, среда, в которой он использовался, удаляется.

Одна вещь, которую вы можете сделать, - это "установить" скриптЭто позволяет вам изменить каталог, потому что по сути вы указываете оболочке выполнять команды из файла, как если бы вы вводили их напрямую.То есть, вы не работаете с копией среды оболочки, вы работаете непосредственно с ней при поиске.

3 голосов
/ 11 августа 2013

Как именно вы можете изменить рабочий каталог bash (или parent в целом)?

Это не возможно при использовании любого «приемлемого» способа. Под приемлемым я подразумеваю «без возмутительного взлома вашей системы (например, используя gdb )»;)

Более серьезно, когда пользователь запускает исполняемый файл, дочерний процесс будет запускаться в собственной собственной среде, которая в основном является копией его родительской среды. Эта среда содержит «переменные среды», а также «текущий рабочий каталог», просто чтобы назвать эти два.

Конечно, процесс может изменить свою собственную среду. Например, чтобы изменить его рабочий каталог (например, когда вы cd xxx в вашей оболочке). Но поскольку эта среда является копией , это никак не влияет на среду родителя. И нет никакого стандартного способа изменить вашу родительскую среду.


В качестве дополнительного примечания, вот почему cd ("chdir") является внутренней командой оболочки, а не внешней утилитой. Если бы это было так, он не смог бы изменить рабочий каталог оболочки.
3 голосов
/ 17 февраля 2012

Способ Я решил это , чтобы иметь псевдоним оболочки, который вызывает сценарий и исходный файл, который написал сценарий. Так, например,

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

Это все еще плохая вещь.

0 голосов
/ 23 августа 2018

Я не уверен, что это ", не делайте этого " тоже ...

Благодаря чрезвычайно полезному обсуждению в https://unix.stackexchange.com/questions/213799/can-bash-write-to-its-own-input-stream/ ...

Утилита tailcd (для "tail-call cd"), которая работает как в bash, так и под Midnight Commander, позволяет использовать в таких скриптах, как

/ бен / mkcd:

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

Реализация сложная и требует xdotool. Команда tailcd должна быть последней командой в сценарии (это типичное требование совместимости для утилит, которые допускают несколько реализаций). Он взламывает поток ввода bash, а именно вставляет в него cd <dirname>. В случае Midnight Commander, он дополнительно вставляет две Ctrl + O (команды включения / выключения панелей) и очень хакерским способом использует sleep для межпроцессной синхронизации (что обидно, но работает).

/ бен / 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, использовать обычное межпроцессное взаимодействие и т. Д.

0 голосов
/ 12 октября 2011

Если вы используете оболочку в интерактивном режиме и целевой каталог статичен, вы можете просто поместить псевдоним в ваш файл ~/.bashrc:

alias cdfoo='cd theFooDir'

При работе с неинтерактивными сценариями оболочки вы можете создать протокол между родительским сценарием Bash и дочерним сценарием Bash. Один из способов реализации этого - позволить дочернему сценарию сохранить путь в файл (например, ~/.new-work-dir). После завершения дочернего процесса родительский процесс должен будет прочитать этот файл (например, cd `cat ~/.new-work-dir`).

Если вы планируете использовать правило, упомянутое в предыдущем абзаце очень часто, я бы посоветовал вам загрузить исходный код Bash и исправить его так, чтобы он автоматически изменял рабочий каталог на содержимое ~/.new-work-dir после каждого запуска команда. В патче вы могли бы даже реализовать совершенно новую встроенную команду Bash, которая соответствует вашим потребностям и реализует протокол, который вы хотите реализовать (эта новая команда, вероятно, не будет принята сопровождающими Bash). Но исправление работает для личного использования и для использования в небольшом сообществе.

...