Я работаю в относительно гетерогенной среде, где я могу использовать разные версии Bash на разных узлах HPC, виртуальных машинах или моей личной рабочей станции. Поскольку я помещаю свои сценарии входа в Git-репозиторий, я хотел бы использовать один и тот же (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
).
источник
.bashrc
. Я все еще хотел записать, как использовать$BASH_VERSINFO
для опроса основную / младшую версию работающей оболочки, для моего собственного назидания, поэтому я закончил публиковать свой собственный ответ.:)
Ответы:
Проверьте,
direxpand
присутствует ли в выходных данныхshopt
и включите его, если это:источник
grep -q '^direxpand\b'
в случае, если у какой-либо будущей версии или ветки bash есть опция, которая содержит это как подстроку и удаляетdirexpand
. Маловероятно в этом конкретном случае, но это не стоит много, чтобы быть надежным.[ -z "$(shopt -po direxpand 2>&-)" ] || shopt -s direxpand
. Больше никаких проблем с регулярными выражениями! :-)[ -n "blah" ] && shopt blah
как бы вы это ни сформулировали, вы говорите: «Если direxpand не поддерживается, то не делайте этого».set -e
в верхней части, поэтому я склонен использовать сокращенную логику для этого.Я не вижу, что не так с перенаправлением ошибок на
/dev/null
. Если вы хотите, чтобы ваш код был устойчивымset -e
, используйте общую идиому… || true
:Если вы хотите запустить некоторый запасной код, если опция не существует, используйте статус возврата
shopt
:Но если вам действительно не нравится перенаправление ошибки, вы можете использовать механизм завершения, чтобы выполнить самоанализ. Это предполагает, что у вас нет устаревших машин с bash ≤ 2.03, которые не имели программируемого завершения.
Этот метод позволяет избежать разветвления, что медленно в некоторых средах, таких как Cygwin. То же самое
2>/dev/null
можно сказать и о простом , я не думаю, что вы можете победить это по производительности.источник
compgen
предложение. Это вещи уровня университета прямо здесь! Избегать перенаправления на/dev/null
это просто личное предпочтение. Я хотел бы попросить разрешения вместо прощения, если это имеет смысл?:)
compgen -A shopt -X ...
даже значило.compgen
этого способа в Unix и Linux , я не знаю, кто первым предложил это. (Я прекратил использовать bash в качестве моей основной оболочки до того, как она завершилась программируемым завершением.) В программировании обычно плохая идея запрашивать разрешение, потому что есть риск, что проверка разрешения не будет соответствовать тому, что вы на самом деле делаете, либо из-за кодирования ошибка (когда вы не совсем проверяете то, что, по вашему мнению, проверяете) или потому что то, что вы проверяли, изменилось до того, как вы его использовали .Когда вы точно знаете, что определенная
shopt
опция доступна в определенной основной / второстепенной версии патча Bash, вы можете проверить$BASH_VERSION
переменную или элементы$BASH_VERSINFO[]
массива, чтобы включить ее условно.Вот тест для Bash 4.2.29 или более поздней версии, где
direxpand
впервые была представлена серия 4.2:Изменить: Чтобы быть ясно, это смешно чрезмерно спроектированное решение для простого игнорирования сообщения об ошибке, исходящего из ваших сценариев входа в систему, но я действительно хотел документировать его независимо от моего, для моего собственного редактирования.
Обратите внимание на скобки вокруг , которые будут необходимы, а также использование и , которые делают целое число , а не (локалите-зависимые) лексические сравнений. Если не заключено в кавычки , RHS оператора рассматривается как шаблоны "extglob" в Bash / условных выражениях , как отмечено здесь , что делает более эстетичным сравнение "начинается с", чем регулярное выражение, IMO.
${BASH_VERSINFO[index]}
-eq
-gt
==
[[
]]
$BASH_VERSINFO
Массив содержит всю информацию , которую вы хотите видеть на выходеbash --version
:Когда не ясно из документации ,
shopt
в которой Bash версии (s) стали поддерживаться или изменить свое поведение, метод , предложенный Лучано отлично:... как и решение, предложенное Жилем, просто игнорировать error (
shopt -s direxpand 2>/dev/null
) и, возможно, проверять,$?
если это абсолютно необходимо.Список литературы: 1 , 2 , 3
Связанное чтение: Сета и Shopt - Почему два?
источник
if [[ $BASH_VERSION > 4.3 ]];
(что соответствует4.3.0
и5.0
т. Д., Но также4.3.0-alpha
. Я не знаю, имеет ли значение более поздний факт.)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
).4.2.0
и наткнулся на тот факт, что это не сработало там. В списке изменений также упоминается, что он добавлен вbash-4.3-alpha
. Тогда я полагаю, что нужно будет${BASH_VERSINFO[2]}
быть точным, но я не знаю, в какой момент релиз добавил это ...