Я пытался вставить вложенную переменную в качестве условия цикла while, но мне не удалось правильно ее расширить.

print_message() {
    timer=0
    timer_condition="$2"

    while [[ $timer_condition ]]; do
        sleep 1
        timer=$((timer+1))
    done
    echo "$1"
}

print_message 'Hello world, 5 seconds passed...' '$timer != "5"'
print_message 'Hello again, another 10 seconds passed...' '$timer != "10"'

В качестве примера я создал простую функцию print_message, которая принимает 2 аргумента: $1 — это сообщение для печати, а $2 — условие, которое я хочу проверить в цикле while, чтобы функция могла получать разные условия для отображения сообщений. Однако цикл while проверяет, истинно ли само $timer_condition, а не его содержимое. Есть ли способ заставить это работать так?

while [[ $timer != "5" ]]; do

Спасибо

0
Radvansky 17 Ноя 2017 в 06:46
Согласитесь, не "вложенные переменные". Больше похоже на анонимную или лямбда-функцию
 – 
fpmurphy
18 Ноя 2017 в 12:49

3 ответа

Лучший ответ

Вы можете использовать eval:

eval: eval [аргумент ...]

Выполнять аргументы как команду оболочки.

Объедините ARG в одну строку, используйте результат в качестве входных данных для оболочки и выполните полученные команды.

Статус выхода: возвращает статус выхода команды или успеха, если команда имеет значение null.

Надуманный пример просто для иллюстрации:

foo=bar
expr='[[ $foo == bar ]]'
if eval "$expr"; then
  echo 'foo is equal to "bar"'
fi

Для вашего скрипта передайте '[[ $timer != 5 ]]' в качестве параметра и используйте

while eval "$timer_condition"; do

Однако имейте в виду, что eval следует использовать с осторожностью, так как его легко использовать, если вы не будете осторожны.

0
B Layer 17 Ноя 2017 в 09:08
Спасибо за ответ, все работает. Однако @fpmurphy1 предоставил хорошую альтернативу, которая, по-видимому, не создает проблем eval. Оба ответа работают в сценарии, который я предоставил, но ваш смог проанализировать более сложное условие, то есть: [[ $(iwconfig wlan0 | grep "ESSID:off") ]]. Можно ли использовать метод @fpmurphy1 для проверки таких условий? Из вашего ответа я предполагаю, что было бы лучше избегать eval, если это возможно.
 – 
Radvansky
17 Ноя 2017 в 13:17
Другой ответ является лучшим ответом, когда он применим, но он применим только для арифметической оценки. Внутри двойных скобок вы можете использовать целочисленные арифметические, логические и побитовые операторы (см. раздел «Арифметическая оценка» man bash). Если это не относится к вам, вы часто можете безопасно использовать eval, если будете осторожны. Вам придется прочитать об этом и решить, что вы хотите делать. (Если только вы используете сценарий или обращаетесь к нему, то это не слишком важно.) Вот хороший сайт (на странице есть примеры «хорошего» eval использования): mywiki.wooledge.org/BashFAQ/048
 – 
B Layer
17 Ноя 2017 в 16:50
Хотел бы я знать, почему кто-то проголосовал за это. Я сделал ошибку? Или вы буквально воспринимаете «eval is evil»?
 – 
B Layer
18 Ноя 2017 в 14:10

Вот один из способов сделать то, что вы хотите сделать:

print_message() {
    timer=0
    timer_condition="$2"

    while (( $timer_condition ))
    do
        sleep 1
        (( timer += 1 ))
    done
    echo "$1"
}

print_message 'Hello world, 5 seconds passed...' 'timer != 5'
print_message 'Hello again, another 10 seconds passed...' 'timer != 10'

~

1
fpmurphy 17 Ноя 2017 в 09:32
Спасибо за ваш ответ, это сработало отлично. По-видимому, по сравнению с альтернативой @b-layer, которая включает использование eval , это будет более простой и безопасный подход. Однако, используя метод @b-layer, я смог передать другое условие, например: $(iwconfig wlan0 | grep "ESSID:off") для печати сообщения «Wi-Fi подключен» в случае подтверждения условия. Можно ли его разобрать по вашему методу?
 – 
Radvansky
17 Ноя 2017 в 12:54
@Radvansky, в этом случае вам обычно нужно использовать eval. Смотрите мой пример
 – 
fpmurphy
18 Ноя 2017 в 05:32

Предположим, вы хотите, чтобы переданное условие было ls -1 | grep demo, где demo — существующий файл, вот фрагмент кода, который работает:

print_message() {
    condition="$2"

    if eval "$condition" > /dev/null
    then
        echo "$1"
    fi
}

print_message 'Found' 'ls -1 | grep demo'
-1
fpmurphy 18 Ноя 2017 в 05:38
Хотел бы я знать, почему кто-то проголосовал за это. Я сделал ошибку? Очередной сторонник «эваль есть зло»?
 – 
fpmurphy
21 Ноя 2017 в 14:46
Я думаю, что кто-то понизил голос из-за eval, уже упомянутого в другом ответе до того, как вы опубликовали.
 – 
林果皞
25 Ноя 2017 в 03:30