Пропустить bash while loop, если функция внутри не выполняет условие - PullRequest
0 голосов
/ 16 ноября 2018

У меня есть цикл while, который строка за строкой читает файл и передает строку нескольким функциям или вложенным функциям внутри цикла.если одна из функций находит что-то не так, я хочу, чтобы цикл while пропустил эту итерацию и перешел к следующей.

Я много искал и пробовал разные вещи, но использование 'continue для пропуска цикла while было единственным решением везде, но, похоже, оно не помогало.Я не уверен, где или как искать что-то подобное.Есть ли решение или другой подход к решению этой проблемы?Спасибо за любую помощь.

   function2(){
   "if some condition that uses $test_name fails, skip the while loop"
  }

  function3(){
   do something
  }

  main_function (){
    do something to $test_name
    function2 $test_name
    function3 $test_name
  }

  while true read -r line; do
    if [[ ! "${line}" =~ ^# && ! -z "${line}" ]]; then
       test_name=$line
        main_function  $test_name 
    fi
 done < $OS_LIST

Ответы [ 3 ]

0 голосов
/ 17 ноября 2018

Мой взгляд на это -

$: cat failout
#! /bin/env bash

OS_LIST=os_list

func1() {
  if [[ -z "$1" ]]
  then echo "ERROR - Empty string!"
       return 1
  fi
}

func2() {
  grep -q foo <<< "$1" || { echo "ERROR - no 'foo'!"; return 1; }
}

func3() { echo "all good here"; }

mainfunc() {
  func1 "$1" || return 1
  func2 "$1" || return 1
  func3 "$1" || return 1
}

while read -r line
do echo "before:[$line]"
   mainfunc "$line" || { echo test failed; continue; }
   echo all tests passed.
done < <( grep -Ev '^[[:space:]]*(#.*)*$' $OS_LIST )

Обратите внимание, что цикл удаляет комментарии и пустые строки с помощью grep перед чтением.

Входной файл os_list с нумерацией строк

$: vi os_list
  1
  2
  3
  4   # shan't
  5
  6 foo bar other stuff
  7
  8 just foo
  9
 10 footed...
 11
 12 bar, without any required string!
 13
 14 more foo
 15
 16

Кстати, некоторые из этих пустых строк имеют пробелы, а некоторые нет.Результаты:

$: failout
before:[foo bar other stuff]
all good here
all tests passed.
before:[just foo]
all good here
all tests passed.
before:[footed...]
all good here
all tests passed.
before:[bar, without any required string!]
ERROR - no 'foo'!
test failed
before:[more foo]
all good here
all tests passed.

Надеюсь, что поможет.Это может быть лучше.Вопросы приветствуются.

0 голосов
/ 17 ноября 2018

Во-первых, напишите функции так, чтобы они возвращали ненулевой статус, если они терпят неудачу, ноль, если они успешны (на самом деле, вы должны делать это в любом случае в качестве общей хорошей практики).Примерно так:

function2() {
    if some condition that uses $test_name fails; then
        echo "test condition failed in function2" >&2    # Error messages should be sent to stderr
        return 1
    fi
    # Code here will only be executed if the test succeeded
    do_something || return 1
    # Code here will only be executed if the test AND do_something both succeeded
    do_something_optional    # No error check here means it'll continue even if this fails
    do_something_else || {
        echo "do_something_else failed in function2" >&2
        return 1
    }
    return 0    # This is actually optional. By default it'll return the status
                # of the last command in the function, which must've succeeded
}

Обратите внимание, что вы можете смешивать стили здесь (if против || против любого), как того требует ситуация.В общем, используйте наиболее понятный стиль, так как ваш самый большой враг - путаница в отношении того, что делает код.

Затем в основной функции вы можете проверить состояние выхода каждой подфункции и вернуться рано, если таковые имеются.fail:

main_function (){
    do something to "$test_name" || return 1    # BTW, you should double-quote variable references
    function2 "$test_name" || return 2    # optional: you can use different statuses for different problems
    function3 "$test_name"  || return 1
}

Если вам нужно пропустить конец основного цикла, вот где вы должны использовать continue:

while true read -r line; do
    if [[ ! "${line}" =~ ^# && ! -z "${line}" ]]; then
        test_name=$line
        main_function "$test_name" || continue
        echo "Finished processing: $line" >&2    # Non-error status messages also go to stderr
    fi
done < "$OS_LIST"
0 голосов
/ 16 ноября 2018

Ну, в функции 2, если тест не пройден:

return 1

В основной функции:

if [[ $? -eq 0 ]]; then
   function3 $test_name
else
   return
fi

Надеюсь, что это может помочь

...