Jak mogę uruchomić polecenie bash po każdej zmianie w $ PWD?


10

zsh zapewnia pewne ładny funkcje przechwytujące , w tym chpwdna prowadzenie funkcji, gdy użytkownik zmienia katalogów.

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

Staram się to naśladować.

Ograniczenia:

  • Musi działać zarówno w interaktywnych, jak i nieinteraktywnych powłokach, co moim zdaniem oznacza, że ​​nie może polegać na czymś takim $PROMPT_COMMAND
  • Nie można przedefiniować cd, ponieważ chcę, aby działał dla każdego polecenia zmieniającego katalogi (np. pushdI popd)
  • Musi działać po komendzie użytkownika, więc trap "my_function" DEBUGnie działa, chyba że mogę w jakiś sposób powiedzieć: „najpierw uruchom $BASH_COMMANDpułapkę, a następnie również zrób to ...”. Widzę, że mogę uniknąć automatycznego uruchamiania, $BASH_COMMAND jeśli extdebug włączono a funkcja pułapki zwraca 1, ale nie sądzę, że chcę wymusić extdebug, a powrót 1do udanej (ale zmodyfikowanej) komendy wydaje się niewłaściwy.

Ostatnia część - „biegnij za poleceniem użytkownika” - jest tym, co mnie obecnie zaskoczyło. Gdybym można uruchomić funkcję po każdym poleceniu, może mam to sprawdzić, czy katalog został zmieniony od ostatniego sprawdzenia. Na przykład:

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
}

Czy jestem na dobrej drodze, czy jest lepszy sposób? Jak mogę uruchomić polecenie w bash po tym, jak użytkownik zmieni katalogi?


3
Dlaczego nie przedefiniować cd, pushdi popd? Ile jest innych sposobów zmiany katalogu?
jw013,

@ jw013 ten kod jest przeznaczony do projektu open source, w którym opiekun wyraźnie nie wymienił definicji cd.
Nathan Long,

Ponadto - „ile innych sposobów jest na zmianę katalogu” - nie wiem, co jest kolejnym powodem, dla którego wolałbym nie polegać na ich jawnym podawaniu.
Nathan Long,

Dlaczego chcesz to zrobić? Twoja funkcja może zahamować wiele programów (C, Java, ..). W skryptach, których używam MYBIN=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )Proszę nie zmieniać zaufanych poleceń Uniksa.
Walter A

1
@NathanLong to tylko dla mojego systemu operacyjnego . System operacyjny wydaje się tutaj nieistotny. Czy system operacyjny ma znaczenie? To jest powłoka, która ma znaczenie w twoim pytaniu i wydaje się, że pytasz konkretnie bash, który działa prawie tak samo na wszystkich systemach operacyjnych, na których działa.
jw013,

Odpowiedzi:


2

Nie ma sposobu, aby sprostać tym ograniczeniom

Wygląda na to, że nie ma sposobu na rozwiązanie tego problemu przez bash z moimi ograniczeniami. Ogólnie możliwe rozwiązania to:

  • Nadpisanie cd, pushdi popd, tak, że każde polecenie, które zmienia katalogów spowoduje uruchomienie funkcji haka. Może to jednak powodować problemy, ponieważ 1) przesłonięcie musi być ostrożne, aby uzupełnić tabulator jak oryginalne polecenie i zwrócić ten sam kod wyjścia oraz 2) jeśli więcej niż jedno narzędzie przyjmuje takie podejście, nie mogą grać dobrze razem
  • Zastąp wszystkie polecenia, które można uruchomić ze zmianami środowiska, aby najpierw uruchomić funkcję przechwytującą. Jest to trudne, ponieważ istnieje wiele takich poleceń
  • 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`, nie po 3) może istnieć tylko jedna funkcja debugowania, więc jeśli inne narzędzie korzysta z tego podejścia, nie mogą grać dobrze razem
  • Przedefiniuj, $PROMPT_COMMANDaby najpierw uruchomić funkcję zaczepu. Jest to nieoptymalne, ponieważ nie będzie działać w nieinteraktywnych powłokach, a ponieważ jeśli inne narzędzie zdefiniuje polecenie, nie będzie mogło grać dobrze razem.

Krótko mówiąc, wydaje się, że jedynym świetnym rozwiązaniem byłoby, gdyby bash dostarczył coś podobnego do chpwd_functionshaka Zshell , ale nie można poprawnie go zasymulować.


1

Jeśli opiekun nie lubi zmiany definicji cd, inną opcją byłoby ponowne zdefiniowanie wszystkich poleceń korzystających z tego środowiska w katalogu:

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

Byłoby to dość wydajne, ponieważ hak PWD i konfiguracja w katalogu byłyby przetwarzane tylko w razie potrzeby.

W twojej przykładowej funkcji check_pwd mogę zmienić:

my_function

do:

my_function "$PWD"

w celu przekazania nowego cwd (może być bardziej modułowy, testowalny).


„redefiniuj wszystkie polecenia korzystające z tego środowiska w katalogu” Niestety nie mogę tego przewidzieć.
Nathan Long,

0

Zainstaluj narzędzia inotify zgodnie z dystrybucją.

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

W moim przykładzie następujące polecenie zostanie ponownie uruchomione, httpdjeśli cokolwiek się zmieni (Modyfikuj, Utwórz, Usuń) w określonym katalogu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.