локализация параметров магазина

Значение дополнительных скобок заключается в том, что они инициализируют массивы в Bash. Это не имеет большого значения при обработке вывода uname -r, состоящего из одного слова, но дляCOMPREPLYэто важно.

Можете убедиться в этом сами:

var1=($(uname -a))
echo $var1
echo ${var1[@]}

2
14.02.2020, 20:03
2 ответа

Да, возможно:

fun(){ local -
       # store state of all options.
       oldstate="$(shopt -p)"


       :
       :

       set +vx; eval "$oldstate"
     }

Существует особый случай с errexit.

0
28.04.2021, 23:23

Я думаю, что нашел решение, которое соответствует моим потребностям, выполнив тело функции в подоболочке . Преимущества и недостатки выполнения тела функции в подоболочке, а также типичные варианты использования обсуждались здесь много раз [1] [2] [3] .

Как указано в [4] , взятом со страницы bash man, общий синтаксис функции

[ function ] name () compound-command [redirection]

A Compound comamandможет быть дочерним процессом текущей оболочки, который инициируется с помощью синтаксиса круглых скобок (list). man bashдает следующее определение (выделение собственным шрифтом):

(list) list is executed in a subshell environment (see COMMAND EXECUTION ENVIRONMENT below). Variable assignments and builtin commands that affect the shell's environment do not remain in effect after the command completes. The return status is the exit status of list.

В моем случае нам нужны две вещи:

  • Локальный эффект изменений опции shoptextglob.
  • Сохранение статуса возврата

Из-за изменений в подоболочке shoptпараметр extglobне будет просачиваться в окружающую оболочку. Кроме того, мы можем вернуться в любой момент из функции. Отрицательным моментом является, конечно, то, что запуск подшелла потребует дополнительных ресурсов.

Демонстрация

Теперь гораздо более короткие функции выглядят так:

yesnoquery () (
    while true; do
        if read -p "$1" answer; then
            shopt -s extglob
            eval '
            case "$answer" in
                @([Yy]|[Yy][Ee][Ss]) ) return 0;; #true
                @([Nn]|[Nn][Oo]) ) return 1;; #false
                * ) echo "Please answer \"yes\" or \"no\"";;   
            esac
            '
        else
            return 2 #reading returned error
        fi
    done
)

В операторе case мы теперь можем напрямую выполнять возврат вместо сохранения во временную переменную.Локализованные переменные больше не нужны, и два условия были сохранены.

То, что параметры shoptдействительно являются локальными, можно быстро увидеть на примере кода из кода в вопросе

#!/bin/bash

# Enable the options globally 
set -u
[[ "$SHELLOPTS" =~ nounset ]] && echo "1: nounset enabled"
shopt -s "extglob"
[[ "$BASHOPTS" =~ extglob ]] && echo "1: extglob enabled"

fun () {
    set +u
    [[ "$SHELLOPTS" =~ nounset ]] || echo "2: nounset disabled"
    shopt -u "extglob"
    [[ "$BASHOPTS" =~ extglob ]] || echo "2: extglob disabled"
}

fun

if [[ "$SHELLOPTS" =~ nounset ]]; then
    echo "3: nounset enabled"
else
    echo "3: nounset disabled"
fi

if [[ "$BASHOPTS" =~ extglob ]]; then
    echo "3: extglob enabled"
else
    echo "3: extglob disabled"
fi

Все, что было изменено, это скобки здесь (вместо{(и удалены лишние локальные переменные ). Выход

1: nounset enabled
1: extglob enabled
2: nounset disabled
2: extglob disabled
3: nounset enabled
3: extglob enabled

показывает, что эффекты были успешно локализованы.

Резюме

Среда выполнения подоболочки как тело функции оказалась полезной для локализации эффектов опций оболочки bash. Операторы caseв теле функции могут извлечь выгоду из extglob, так как изменения этой переменной не повлияют на код вне области действия функции. Если ресурсов не хватает, дополнительные накладные расходы на запуск подоболочки могут излишне ухудшить производительность.

0
28.04.2021, 23:23

Теги

Похожие вопросы