Pracuję w stosunkowo heterogenicznym środowisku, w którym mogę uruchamiać różne wersje Bash na różnych węzłach HPC, maszynach wirtualnych lub mojej osobistej stacji roboczej. Ponieważ umieściłem swoje skrypty logowania w repozytorium Git, chciałbym używać tego samego (ish) na .bashrc
całym forum, bez zbyt wielu „jeśli ten host, to ...” - niechlujny typ.
Podoba mi się domyślne zachowanie Bash ≤ 4.1, które rozwija cd $SOMEPATH
się cd /the/actual/path
po naciśnięciu Tabklawisza. W wersji Bash 4.2 i nowszych konieczne byłoby shopt -s direxpand
ponowne włączenie tego zachowania, które stało się dostępne dopiero w wersji 4.2.29 . To tylko jeden przykład; inna, prawdopodobnie powiązana shopt
opcja complete_fullquote
(chociaż nie wiem dokładnie, co to robi) mogła również zmienić domyślne zachowanie w wersji 4.2.
Jednak direxpand
nie jest rozpoznawane przez wcześniejsze wersje Basha, a jeśli próbuję shopt -s direxpand
w moim .bashrc
, który powoduje wyświetlenie komunikatu o błędzie, który jest drukowany na konsoli przy każdym logowaniu do węzła ze starszą Bash:
-bash: shopt: direxpand: invalid shell option name
Chciałbym owinąć warunek, shop -s direxpand
aby włączyć tę opcję w wersji Bash> 4.1 w niezawodny sposób, bez przecierania starszych wersji Bash ( tj. Nie tylko przekierowując wyjście błędu /dev/null
).
źródło
.bashrc
. Wciąż potrzebowałem zapisu, w jaki sposób użyć$BASH_VERSINFO
do przesłuchania głównej / podrzędnej wersji działającej powłoki, dla mojej własnej edycji, dlatego skończyłem publikować własną odpowiedź.:)
Odpowiedzi:
Sprawdź, czy
direxpand
jest obecny na wyjściushopt
i włącz go, jeśli:źródło
grep -q '^direxpand\b'
spraw, aby w przypadku, gdy w przyszłej wersji lub rozwidleniu bash będzie dostępna opcja, która zawiera to podciąg i usuwadirexpand
. Jest mało prawdopodobne w tym konkretnym przypadku, ale solidność nie kosztuje wiele.[ -z "$(shopt -po direxpand 2>&-)" ] || shopt -s direxpand
. Nigdy więcej problemów z wyrażeniami regularnymi! :-)[ -n "blah" ] && shopt blah
sposób, w jaki to wyrażasz, mówisz „jeśli direxpand nie jest obsługiwany, to nie rób tego”.set -e
na górze, więc zwykle używam logiki skrótowej w ten sposób.Nie widzę, co jest nie tak z błędami przekierowywania
/dev/null
. Jeśli chcesz, aby Twój kod był niezawodnyset -e
, użyj wspólnego idiomu… || true
:Jeśli chcesz uruchomić kod zastępczy, jeśli opcja nie istnieje, użyj statusu zwracanego
shopt
:Ale jeśli naprawdę nie lubisz przekierowywać błędu, możesz użyć mechanizmu uzupełniania do przeprowadzenia introspekcji. Zakłada się, że nie masz przestarzałych maszyn z bash ≤ 2.03, które nie miałyby programowalnego zakończenia.
Ta metoda pozwala uniknąć rozwidlenia, które jest powolne w niektórych środowiskach, takich jak Cygwin. Tak też jest proste
2>/dev/null
, nie sądzę, że można to pobić pod względem wydajności.źródło
compgen
propozycja. To są rzeczy na poziomie uniwerek! Unikanie przekierowania do/dev/null
jest tylko osobistą preferencją. Chciałbym prosić o pozwolenie zamiast wybaczenia, jeśli to ma sens?:)
compgen -A shopt -X ...
ogóle oznacza.compgen
ten sposób w systemach Unix i Linux , nie wiem, kto pierwszy to zaproponował. (Przestałem używać bash jako mojej głównej powłoki, zanim zakończyło się programowanie). W programowaniu zwykle złym pomysłem jest poprosić o pozwolenie, ponieważ istnieje ryzyko, że sprawdzenie uprawnień nie będzie pasować do tego, co faktycznie robisz, albo z powodu kodowania błąd (gdy nie do końca sprawdzasz, co myślisz, że sprawdzasz) lub ponieważ to, co sprawdziłeś, zmieniło się przed użyciem .Gdy wiesz na pewno, że konkretna
shopt
opcja jest dostępna w określonym wydaniu Bash w wersji głównej / drugorzędnej / łaty, możesz sprawdzić$BASH_VERSION
zmienną lub elementy$BASH_VERSINFO[]
tablicy, aby włączyć ją warunkowo.Oto test dla wersji Bash 4.2.29 lub nowszej, w której
direxpand
po raz pierwszy wprowadzono serię 4.2:Edycja: Żeby było jasne, jest to absurdalnie przeprojektowane rozwiązanie, aby po prostu zignorować komunikat o błędzie pochodzący z twoich skryptów logowania, ale ja chciałem to udokumentować niezależnie od mojej własnej edycji.
Zwróć uwagę na nawiasy klamrowe , które są wymagane, oraz użycie i , które wykonują liczby całkowite zamiast (zależne od ustawień regionalnych) leksykalne porównania. Jeśli nie jest cytowany , RHS operatora traktowane są jako wzorce „extglob” w Bash / warunkowe, jak zauważono tutaj , co sprawia, że bardziej estetyczne porównanie „zaczyna się od” niż regex, IMO.
${BASH_VERSINFO[index]}
-eq
-gt
==
[[
]]
$BASH_VERSINFO
Tablica zawiera wszystkie informacje chcesz widzieć na wyjściubash --version
:Jeśli z dokumentacji nie wynika jasno,
shopt
w jakich wersjach Bash obsługiwano lub zmieniano ich zachowanie, metoda zaproponowana przez Luciano jest w porządku:... podobnie jak rozwiązanie zaproponowane przez Gillesa polegające na ignorowaniu błędu (
shopt -s direxpand 2>/dev/null
) i sprawdzeniu,$?
czy jest to absolutnie konieczne.Odniesienia: 1 , 2 , 3
Powiązana lektura: Zestaw i Shopt - dlaczego dwa?
źródło
if [[ $BASH_VERSION > 4.3 ]];
(co odpowiada4.3.0
,5.0
etc., ale też4.3.0-alpha
nie wiem, czy późniejszych faktów sprawach.).direxpand
opcja ta jest rzeczywiście dostępna dla Bash 4.2; Sprawdziłem to za pomocą obrazu Docker w wersji 4.2.53, uruchamiającdocker run --rm bash:4.2 bash -c shopt | grep direxpand
(i dla pewności, że rzeczywiście nie jest dostępny w wersji 4.1.17 przez uruchomieniedocker run --rm bash:4.1 bash -c shopt | grep direxpand
).4.2.0
i natknąłem się na fakt, że tam nie działało. Dziennik zmian wspomina również, że został dodanybash-4.3-alpha
. Podejrzewam, że wtedy trzeba by${BASH_VERSINFO[2]}
to dokładnie sprawdzić , ale nie wiem, która wersja wydania go dodała ...