Як я можу запустити команду в bash після будь-якої зміни $ PWD?


10

zsh надає кілька приємних функцій гака , в тому числі chpwdдля запуску функції після зміни користувачем каталогів.

# zsh only
function greet() { echo 'hi'; }
chpwd_functions+=("greet")
cd .. # hi
pushd # hi
popd  # hi

Я намагаюся наслідувати це в баш.

Обмеження:

  • Він повинен працювати як в інтерактивних, так і в неінтерактивних оболонках, що, на мою думку, означає, що він не може покладатися на щось подібне $PROMPT_COMMAND
  • Він не може перевизначити cd, тому що я хочу, щоб він працював для будь-якої команди, яка змінює каталоги (наприклад, pushdі popd)
  • Він повинен працювати після команди користувача, тому trap "my_function" DEBUGне працює, якщо я не можу якось сказати там: "спочатку запустіть $BASH_COMMANDми в пастці, а потім зробіть це ..." Я бачу, що я можу уникнути автоматичного запуску, $BASH_COMMAND якщо extdebug ввімкнено і функція пастки повертає 1, але я не думаю, що я хочу змусити extdebug, і повернення 1для успішної (але модифікованої) команди здається неправильним.

Остання частина - «запустити за командою користувача» - це те, що зараз мене наткнуло. Якщо я можу запускати функцію після кожної команди, я можу її перевірити, чи змінився каталог з моєї останньої перевірки. Наприклад:

function check_pwd() {
  # true in a new shell (empty var) or after cd
  if [ "$LAST_CHECKED_DIR" != "$PWD" ]; then
    my_function
  fi
  LAST_CHECKED_DIR=$PWD
}

Я на правильному шляху, чи є кращий шлях? Як я можу запустити команду в bash після того, як користувач змінить каталоги?


3
Чому б не переглянути cd, pushdі popd? Скільки інших способів змінити каталог?
jw013

@ jw013 цей код призначений для участі у проекті з відкритим кодом, де сервіс спеціально вказав, що не переосмислюється cdяк принцип.
Натан Лонг

Також - "скільки інших способів змінити каталог" - я не знаю, що є ще однією причиною, яку я вважаю за краще не покладатися на їх чіткий перелік.
Натан Лонг

Чому ти хочеш це робити? Ваша функція може гальмувати багато програм (C, Java, ..). У сценаріях, які я використовую MYBIN=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )Будь ласка, не змінюйте довірені команди Unix.
Вальтер А

1
@NathanLong , це лише для моєї операційної системи . Операційна система тут видається неактуальною. Чи має значення ОС? Ця оболонка має значення у вашому запитанні, і ви, схоже, конкретно запитуєте bash, яка працює майже однаково у всіх операційних системах, на яких вона працює.
jw013

Відповіді:


2

Ні в якому разі не можна відповідати цим обмеженням

Схоже, немає ніякого способу вирішити цю проблему за рахунок моїх обмежень. Загалом можливими рішеннями є:

  • Переопределить cd, pushdі popd, так що будь-яка команда, яка змінює каталоги, спочатку запустить функцію гака. Але це може створити проблеми, оскільки 1) переосмислення повинно бути обережним, щоб вкладка була завершена як оригінальна команда і повертала той самий код виходу, і 2) якщо більше одного інструменту застосовує такий підхід, вони не можуть добре грати разом
  • Перезазначте всі команди, які можна виконати зі змінами середовища, щоб спочатку запустити функцію гачка. Це важко, тому що таких команд багато
  • trap 'my_functionDEBUG so that every command will run the hook function. This is suboptimal because 1) it runs before every command, 2) it runs *before*cd`, не після 3) може бути лише одна функція налагодження, тому якщо інший інструмент використовує такий підхід, вони не можуть добре грати разом
  • Повторно визначте, $PROMPT_COMMANDщоб спочатку запустити функцію гака. Це неоптимально, оскільки він не працюватиме в неінтерактивних оболонках, і тому, що якщо інший інструмент визначає команду підказок, вони не можуть добре грати разом.

Коротше кажучи, здається, що єдиним чудовим рішенням було б, якби Баш забезпечив щось на кшталт гачка zshell chpwd_functions, але, здається, неможливо правильно їх моделювати.


1

Якщо сервісу не подобається, що ви змінюєте визначення для cd, іншим варіантом буде переосмислити всі команди, які використовують це середовище в каталозі:

for c in cmd1 cmd2 cmd3 cmd4 cmd5 ; do
    eval "$c() { check_pwd ; command $c \"\$@\" ; }"
done

Це було б досить ефективно, тому що PWD-гак та конфігурація в каталозі обробляться лише за потреби.

У вашому прикладі check_pwd функції я можу змінити:

my_function

до:

my_function "$PWD"

для того, щоб перейти у новий cwd (може бути більш модульним, тестуваним).


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

0

Встановіть інструменти inotify відповідно до вашого розповсюдження.

inotifywait -emodify,create,delete -m /path/to/directory | while read line; do service httpd reload; done

У моєму прикладі наступна команда перезапуститься, httpdякщо щось зміниться (Змінити, Створити, Видалити) у вказаному каталозі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.