Як я можу запобігти виникненню помилок у моєму .bashrc непідтримувані параметри "shopt"?


9

Я працюю у відносно неоднорідному середовищі, де я можу запускати різні версії Bash на різних вузлах HPC, VM або моїй персональній робочій станції. Оскільки я розміщую свої скрипти для входу в Git repo, я хотів би використовувати те саме (ish) .bashrcпо всій дошці, без великої кількості "якщо цей хост, то ..." - безладдя.

Я як поведінка за умовчанням Bash ≤ 4.1, розширюється cd $SOMEPATHв cd /the/actual/pathпри натисканні на Tabклавішу. У Bash 4.2 і вище, вам потрібно буде shopt -s direxpandповторно включити таку поведінку, і що Герасимчука є до 4.2.29 . Це лише один приклад; інший, можливо, пов'язаний shoptваріант complete_fullquote(хоча я не знаю точно, що це робить), можливо, також змінив поведінку за замовчуванням на v4.2.

Однак, direxpandпопередні версії Bash не розпізнаються, і якщо я спробую зробити shopt -s direxpandсвою .bashrc, це призводить до того, що повідомлення про помилку друкується на консоль кожного разу, коли я входжу у вузол зі старшим Bash:

-bash: shopt: direxpand: invalid shell option name

Що я хотів би зробити, це обернути умовно, shop -s direxpandщоб увімкнути цю опцію на Bash> 4.1 надійним способом, не розтушовуючи старіші версії Bash ( тобто , не просто перенаправляючи вихідну помилку на /dev/null).


Як моя відповідь не допомогла?
Luciano Andress Martini

@LucianoAndressMartini Це і було, і це рішення, з яким я закінчився .bashrc. Я все ще хотів записати, як використовувати $BASH_VERSINFOдля допиту основної / другорядної версії запущеної оболонки для мого власного називання, саме тому я закінчив публікувати власну відповідь. :)
TheDudeAbides

Подивіться у мою відповідь, у мене є щось про порівняння версії програм із скриптом оболонки.
Лучано Андресс Мартіні

Відповіді:


14

Перевірте, чи direxpandє присутність у висновку shoptта включіть його, якщо він є:

shopt | grep -q '^direxpand\b' && shopt -s direxpand

4
Краще зробіть це, grep -q '^direxpand\b'якщо у будь-якій майбутній версії або fork bash є опція, яка містить це як підрядку та видаляє direxpand. Навряд чи в цьому конкретному випадку, але бути надійним не варто.
перестань бути злим"

Дякую Лучано. Я мав намір відповісти на власне запитання, але я прийму вашу відповідь після того, як мої правки пройдуть експертну перевірку. Можливо, ви можете їх схвалити самостійно?
TheDudeAbides

4
Bash дозволяє запитувати конкретні параметри оболонки, тому можна використовувати [ -z "$(shopt -po direxpand 2>&-)" ] || shopt -s direxpand. Більше не виникає проблем з регулярними виразами! :-)
Девід

@DavidFoerster Я б обернув логіку: [ -n "blah" ] && shopt blahяк ви це формулюєте, ви говорите "якщо direxpand не підтримується, тоді не робіть цього".
Багатий

1
@Rich: Більшість моїх скриптів оболонок містяться set -eвгорі, тому я, як правило, використовую логіку скорочень.
Девід

16

Я не бачу, що не так у помилках переадресації /dev/null. Якщо ви хочете, щоб ваш код був надійним set -e, використовуйте загальну фразу … || true:

shopt -s direxpand 2>/dev/null || true

Якщо ви хочете запустити якийсь резервний код, якщо опція не існує, використовуйте статус повернення shopt:

if shopt -s direxpand 2>/dev/null; then
   # the direxpand option exists
else
   # the direxpand option does not exist
fi

Але якщо ви дійсно не любите перенаправлення помилки далеко, ви можете використовувати механізм завершення для здійснення самоаналізу. Це передбачає, що у вас немає старовинних машин з bash ≤ 2,03, які не мали програмованого завершення.

shopt_exists () {
  compgen -A shopt -X \!"$1" "$1" >/dev/null
}
if shopt_exists direxpand; then
  shopt -s direxpand
fi

Цей метод дозволяє уникнути розгортання, який у деяких середовищах, таких як Cygwin, повільний. Так само і прямо 2>/dev/null, я не думаю, що ви можете це перемогти в продуктивності.


Це НЕ де мій мозок би вже пішов, але я , як compgenпропозиція. Це вміст рівня різноманітності прямо там! Уникати переадресації - /dev/nullце лише особисті переваги. Мені подобається просити дозволу замість прощення, якщо це має сенс? :)
TheDudeAbides

+1 за абсолютно непередбачуване навчання в програмуванні Bash, що змусило мене перейти до посібника, щоб розшифрувати, що compgen -A shopt -X ...навіть означало.
TheDudeAbides

4
@TheDudeAbides Я читав про використання compgenцього способу на Unix & Linux , не знаю, хто вперше запропонував це. (Я перестала використовувати bash як свою основну оболонку до того, як вона закінчилася програмуванням.) У програмуванні зазвичай погана ідея просити дозволу, оскільки існує ризик того, що перевірка дозволу не буде відповідати тому, що ви насправді робите, або через кодування. помилка (де ви не зовсім перевіряєте те, що ви думаєте, що перевіряєте) або тому, що те, що ви перевірили, змінилося до того, як ви його використали .
перестань бути злим"

5

Коли ви точно знаєте, що певний shoptваріант доступний під час певного основного / мінорного / виправлення виправлень Bash, ви можете перевірити $BASH_VERSIONзмінну або елементи $BASH_VERSINFO[]масиву, щоб умовно включити її.

Ось тест на Bash 4.2.29 або новішої версії, версію, де direxpand вперше було представлено до серії 4.2:

if [[ $BASH_VERSION == 4.2.* && ${BASH_VERSINFO[2]} -ge 29 ]] ||
   [[ ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -ge 3 ]] ||
   [[ ${BASH_VERSINFO[0]} -ge 5 ]]; then
    shopt -s direxpand
fi

Редагувати: Щоб зрозуміти, це смішне надмірно розроблене рішення для простого ігнорування повідомлення про помилку, що надходить із ваших скриптів для входу, але я хотів задокументувати його незалежно, для мого власного зведення.

Зверніть увагу на дужки навколо , які є необхідними, і використання та , які роблять цілі, а не (залежні від локальності) лексичні порівняння. Якщо без котирування, РЗС оператора трактується як "extglob" шаблони в Bash / conditionals, як зазначалося${BASH_VERSINFO[index]}-eq-gt==[[]] тут , що робить більш естетичним порівняння "починається з", ніж регекс, IMO.

$BASH_VERSINFOМасив містить всю інформацію , яку ви хочете бачити на виході bash --version:

bash --version | head -1
# result:
# GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)

declare -p BASH_VERSINFO
# result:
# declare -ar BASH_VERSINFO='([0]="4" [1]="3" [2]="48" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")'

Коли НЕ ясно з документації , shoptв якій Bash версії (s) стали підтримуватися або змінити свою поведінку, метод , запропонований Лучано відмінно:

# note the '-q' so that the matched pattern isn't actually printed
shopt | grep -q direxpand && shopt -s direxpand

... як рішення, запропоноване Жилем, просто ігнорувати помилку (shopt -s direxpand 2>/dev/null ), і, можливо, перевірити, $?якщо це абсолютно необхідно.

Список літератури: 1 , 2 , 3
Пов'язане читання: Встановити та зняти - Чому два?


Ви могли б також бути в змозі використати що - щось на зразок if [[ $BASH_VERSION > 4.3 ]];(що відповідає 4.3.0, і 5.0т.д., але і 4.3.0-alphaя не знаю , якщо наступні питання , фактично.)
ilkkachu

Привіт @ilkkachu. Дякуємо за вашу редакцію, що охоплює Bash v5.x. Цей direxpandваріант дійсно доступний для Bash 4.2; Я перевірив це з Докер зображенням на v4.2.53, запустивши docker run --rm bash:4.2 bash -c shopt | grep direxpand(і, для гарної заходи, що це дійсно НЕ є на v4.1.17, запустивши docker run --rm bash:4.1 bash -c shopt | grep direxpand).
TheDudeAbides

ах добре, я перевірив 4.2.0і натрапив на те, що він там не працює. Журнал змін також згадує його, що додається bash-4.3-alpha. Я гадаю, що тоді потрібно було б перевірити, ${BASH_VERSINFO[2]}щоб бути точним щодо цього, але я не знаю, який пункт випуску додав його ...
ilkkachu

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