2017-01-31 27 views
0

Не уверен, что это возможно, но я пытаюсь вырваться из инструкции if, которая находится в цикле while. Однако я не хочу выходить из цикла while. Я попытался использовать exit и break, но оба выхода из цикла while.Выйти из оператора if во время цикла

Проблема в том, что я не знаю, в какой папке находится файл, который я ищу, поэтому я хочу выйти из текущего оператора if, когда я сопоставляю искомый файл, чтобы я мог перейти к следующий серийный номер.

У меня есть текстовый файл drives-fw-sn.txt, который содержит список серийных номеров. Структура коды:

  • Я прочитал в одном серийном номере на время от drives-fw-sn.txt используя while петли
  • I поиск файла с именем output_log использованием find
  • Я тогда напечатать первое вхождение серийного номера из найденного файла
  • Далее я печатаю, что журнал был найден и хочу

Вот отрывок из моего кода (там более трех тестовых папок). Обратите внимание, что он все еще содержит команды exit, которые выходят из цикла while.

while read node; do 
    if find ./test1/*log* -maxdepth 2 -type f -name output_log -exec egrep -m 1 $node {} \; ; then 
    echo "Log SN $node available" 
    exit 1 
    fi 
    if find ./test2/*log* -maxdepth 2 -type f -name output_log -exec egrep -m 1 $node {} \; ; then 
    echo "Log SN $node available" 
    exit 1 
    fi 
    if find ./test3/*log* -maxdepth 2 -type f -name output_log -exec egrep -m 1 $node {} \; ; then 
    echo "Log SN $node available" 
    exit 1 
    fi 
done < drives-fw-sn.txt 
+0

Вы пробовали использовать аргумент case в bash? –

+0

@KaranShah Я думал об использовании оператора case, но я не думаю, что он был бы очень подходит для моего приложения. – stevo

+0

Состояние выхода 'find' не связано с статусом выхода команды, выполняемой с помощью' -exec', или сколько файлов найдено 'find'. Статус выхода равен 0, если в работе 'find' нет реальной ошибки. – chepner

ответ

0

Невозможно вырваться из if, само по себе. Но из внешнего вида вашего примера вы можете использовать команду continue вместо exit, чтобы перебрать цикл сразу.

0

continue - правильный ответ на ваш конкретный вопрос, как «вырваться» из if. Имейте в виду, что проверка if на самом деле не проверяет успешность grep, см. Комментарий от chepner.

Я хотел бы сделать это таким образом, что обходит эту проблему, в первую очередь:

Поскольку вы не знаете, какой каталог файл, содержащий серийный номер будет в, это не имеет значения в который приказывает вам смотреть на них. Вместо того, чтобы перечислить все каталоги отдельно и запустить find -exec на каждом из них, вы можете Grep просто попробовать все файлы журналов непосредственно:

while read -r node; do 
    cat **/output_log | grep -m 1 "$node" && echo "Log SN $node available" 
done < drives-fw-sn.txt 

Это требует вариант оболочки globstar, shopt -s globstar, чтобы включить **/ конструкцию. В зависимости от структуры вашего каталога вам может и не понадобиться, и вместо этого можно использовать что-то вроде test*/*log*/output_log.

cat Используется для предотвращения того, чтобы grep проверял другие файлы, как только он нашел совпадение.

Результат немного отличается: совпадения предваряются именем файла, но его можно настроить с помощью соответствующих параметров grep (-h для подавления имен файлов).

Также похоже, что вам не требуется регулярное выражение; если это так, вы можете использовать grep -F для фиксированных строк, которые должны быть быстрее.

Наконец, в зависимости от того, как выглядят серийные номера, вы можете использовать опцию -w (совпадение только с полными словами), чтобы избежать ложных срабатываний из-за совпадений подстроки.

+0

Я не указал здесь в этом вопросе, но я не могу напрямую использовать grep, потому что в каталогах слишком много файлов, и использование grep таким образом будет использовать слишком много полосы пропускания. Использование find сначала, а затем grep устраняет эту проблему. – stevo

+0

@stevo Что вы подразумеваете под «Слишком большая пропускная способность»? Слишком длинная командная строка? –

+0

По полосе пропускания я имел в виду, что поиск использует слишком много ресурсов на сервере и останавливает операции. Метод find и grep меньше обременяет ресурсы – stevo

1

Это на самом деле довольно просто, используя встроенный return. Внутри цикла while установите оператор if внутри небольшого функционального блока. Когда во время итераций выполняется условие if, вы можете вызвать его return, где сценарий вернется в место, где функция была вызвана и продолжена с этой точки. Я покажу вам пример:

#!/bin/bash 

read -p 'Input: ' HEY 

func() { if true; then return; fi; } 

while true; do 

    echo "Input received!" 
    func && break 

done 

В функции func, у вас есть очень простой if заявление, которое может содержать любое условное значение, которое вы хотите, например, как ваши несколько условий. Когда вы включаете ключевое слово return, оператор if затем отправит «счетчик программ» интерпретатора, если вы хотите, вернуться к точке, где была вызвана функция func. Который в этом случае находится внутри петли while. Так будет, как будто функция даже не вызывается, и, как вы можете видеть, следующая команда в цикле while - это ключевое слово break, которое завершит цикл while. Функция, которая содержит код if-then-return, может быть внутри ИЛИ вне вашего цикла while, если условия, которые вы помещаете внутри оператора if, были загружены сначала в интерпретатор (bash считывает скрипты сверху вниз, подобно тому, как загружается C-код).

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

#!/bin/bash 

MAIN() { 
read -p 'Input: ' HEY 

while true; do 

    if [ "$HEY" == "hello" ]; then 
     return 
    else 
     echo "Incorrect input! Try again!" 
     MAIN 
    fi 

done 
} 

MAIN 

echo "Correct input received!" 

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

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