Можно ли программно изменить рабочий каталог родительской оболочки?

8

Я хочу написать некоторый код, который позволит мне переключаться на некоторые каталоги, в которые я обычно хожу. Скажем, эта программа mycdи /a/very/long/path/nameкаталог, в который я хочу перейти.

Так что я могу просто напечатать mycd 2вместо cd /a/very/long/path/name. Здесь я предполагаю, что mycdзнает 2относится к этому /a/very/long/path/name. Там также может быть mycd 1, mycd 3... и т.д.

Проблема в том, что мне нужно написать mycdкак сценарий оболочки и набрать, . mycd 2чтобы выполнить желаемую вещь, потому что в противном случае сценарий просто исполняется в дочернем сценарии, который ничего не меняет в родительской оболочке, которая мне действительно нужна.

Мой вопрос:

  • я могу сделать это без использования source? потому что . mycdпредполагает, что mycdэто должен быть скрипт оболочки, и это может также привести к появлению некоторых функций, которые мне не нужны.

  • я могу реализовать это на некоторых других языках программирования?

Javran
источник

Ответы:

23

создайте mycdфункцию, чтобы cdкоманда выполнялась в вашей текущей оболочке. Сохраните его в вашем файле ~ / .bashrc.

function mycd {
    if (( $# == 0 )); then
        echo "usage: $FUNCNAME [1|2|3|...]"
        return
    fi
    case $1 in
        1) cd /tmp ;;
        2) cd /a/very/long/path/name ;;
        3) cd /some/where/else ;;
        *) echo "unknown parameter" ;;
    esac
}
Гленн Джекман
источник
Спасибо, не думал об использовании функций, и это только позволяет все: теперь я могу позволить mycdперейти $@к любой программе , мне нравится.
Javran
Убедитесь, что вы цитируете, "$@"чтобы любые аргументы, содержащие пробелы, обрабатывались правильно.
Гленн Джекман
9

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

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

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

Жиль "ТАК - перестань быть злым"
источник
1
На самом деле есть шанс заставить его «работать», но он нетривиален, подвержен ошибкам и его следует избегать любой ценой. Для того, чтобы показать , что это на самом деле «возможно», рассмотреть этот скрипт , где родитель Bash: ws=$1; gdb -p $(ps h -o ppid -p $$) -ex "call chdir(\"$wd\")" -ex "call set_working_directory(\"$wd\")" -ex detach -ex q -batch. Выполнить как braindead-cd-parent /. Вы увидите, что pwdвозвращается /и так ведет lsсебя. Но подсказка ( PS1) остается неизменной, глаза болят и т. Д. Поэтому не делайте этого, даже если это возможно.
Лекенштейн
1
@Lekensteyn Это ptraceметод, который я упоминаю. Это хорошо работает на программах, которые не заботятся о своем текущем каталоге. В оболочке многие вещи ( PWDпеременные, подсказки и т. Д.) Могут стать неправильными, и оболочка может аварийно завершить работу или неправильно работать.
Жиль "ТАК - перестать быть злым"
5

Как вы указали сами, сценарии оболочки всегда выполняются в подоболочке, которая не может влиять на ее родительскую оболочку.

Вы можете однако ...

  • используйте псевдоним:
    alias mycd2='cd /a/very/long/path/name'
  • ваш скрипт 1 выведет правильную команду оболочки ...

    #!/bin/bash
    if [ "x$1" = "x2" ]
    then
        echo "cd /a/very/long/path/name"
    fi

    ... и выполнить вывод: $(mycd 2)

1: Вы, вероятно, захотите использовать caseутверждение, а не ifусловие в примере.

n.st
источник
5
Псевдоним проходим. Сценарий - это та же проблема, что и у него. Этот вопрос кричит о функции оболочки.
Рикки Бим