Как сделать паузу в скрипте bash

Обновлено: 05.07.2024

break выход из цикла for, while или until
continue выполнение следующей итерации цикла for, while или until
echo вывод аргументов, разделенных пробелами, на стандартное устройство вывода
exit выход из оболочки
export отмечает аргументы как переменные для передачи в дочерние процессы в среде
hash запоминает полные имена путей команд, указанных в качестве аргументов, чтобы не искать их при следующем обращении
kill посылает сигнал завершения процессу
pwd выводит текущий рабочий каталог
read читает строку из ввода оболочки и использует ее для присвоения значений указанным переменным.\
return заставляет функцию оболочки выйти с указанным значением
shift перемещает позиционные параметры налево
test вычисляет условное выражение
times выводит имя пользователя и системное время, использованное оболочкой и ее потомками
trap указывает команды, которые должны выполняться при получении оболочкой сигнала
unset вызывает уничтожение переменных оболочки
wait ждет выхода из дочернего процесса и сообщает выходное состояние.

И конечно же кроме встроенных команд мы будем использовать целую кучу внешних, отдельных команд-программ, с которыми мы познакомимся уже в процессе

Что необходимо знать с самого начала

  1. Любой bash-скрипт должен начинаться со строки:

Переменные и параметры скрипта

Приведу как пример небольшой пример, который мы разберем:

Результат выполнения скрипта:

ite@ite-desktop:~$ ./test.sh qwerty
Вы запустили скрипт с именем ./test.sh и параметром qwerty
Вы запустили скрипт с именем $script_name и параметром $parametr1

После того как мы познакомились как использовать переменные и передавать скрипту параметры, время познакомиться с зарезервированными переменными:

Условные операторы, думаю, знакомы практически каждому, кто хоть раз пытался на чем-то писать программы. В bash условия пишутся след. образом (как обычно на примере):

Результат выполнения скрипта:

ite@ite-desktop:~$ ./primer2.sh 1 1
Применик 1 и источник 1 один и тот же файл!

ite@ite-desktop:~$ ./primer2.sh 1 2
Удачное копирование!

Структура if-then-else используется следующим образом:

В качестве команд возвращающих код возврата могут выступать структуры [[ , [ , test, (( )) или любая другая(или несколько) linux-команда.

test - используется для логического сравнения. после выражения, неоьбходима закрывающая скобка "]"
[ - синоним команды test
[[ - расширенная версия "[" (начиная с версии 2.02)(как в примере), внутри которой могут быть использованы || (или), & (и). Долна иметь закрывающуб скобку "]]"
(( )) - математическое сравнение.

для построения многоярусных условий вида:

для краткости и читаемости кода, можно использовать структуру:

Условия. Множественный выбор

Если необходимо сравнивать какоую-то одну переменную с большим количеством параметров, то целесообразней использовать оператор case.

ite@ite-desktop:~$ ./menu2.sh
Выберите редатор для запуска:
1 Запуск программы nano
2 Запуск программы vi
3 Запуск программы emacs
4 Выход

После выбор цифры и нажатия Enter запуститься тот редактор, который вы выбрали(если конечно все пути указаны правильно, и у вас установлены эти редакторы :) )

Прведу список логических операторв, которые используются для конструкции if-then-else-fi:

С основами языка и условиями мы разобрались, чтобы не перегружать статью, разобью её на несколько частей(допустим на 3). Во второй части разберем операторы цикла и выполнение математических операций.

Циклы. Цикл for-in.

Оператор for-in предназначен для поочередного обращения к значениям перечисленным в списке. Каждое значение поочередно в списке присваивается переменной.
Синтаксис следующий:

Рассмотрим небольшой пример:

После выполнения примера в первых 5 виртуальных консолях(терминалах) появится строка с её номером. В переменную $i поочередно подставляются значения из списка и в цикле идет работа со значением этой переменной

Циклы. Цикл while.

Цикл while сложнее цикла for-in и используется для повторения команд, пока какое-то выражение истинно( код возврата = 0).
Синтаксис оператора следующий:

Пример работы цикла рассмотрим на следующем примере:

А теперь результат работы скрипта:

Теперь об условии истинности. После while , как и в условном операторе if-then-else можно вставлять любое выражение или команду, которая возвращает код возврата, и цикл будет исполнятся до тех пор, пока код возврата = 0! Оператор [ аналог команды test , которая проверяет истинность условия, которое ей передали.

Рассмотрим еще один пример, я взял его из книги Advanced Bash Scripting. Уж очень он мне понравился :), но я его немного упростил. В этом примере мы познакомимся с еще одним типом циклов UNTIL-DO. Эта практически полный аналог цикла WHILE-DO, только выполняется пока какое-то выражение ложно.
Вот пример:

Результат выполнения скрипта:

Команда let .
Команда let производит арифметические операции над числами и переменными.
Рассмотрим небольшой пример, в котором мы производим некоторые вычисления над введенными числами:

Ну вот, как видите ничего сложного, список математических операций стандартный:

+ — сложение
— — вычитание
* — умножение
/ — деление
** — возведение в степень
% — модуль(деление по модулю), остаток от деления
let позволяет использовать сокращения арифметических команд, тем самым сокращая кол-во используемых переменных. Например: a = a+b эквивалентно a +=b и т.д

Работа с внешними программами при написании shell-скриптов

Для начала немного полезной теории.

В bash (как и многих других оболочках) есть встроенные файловые дескрипторы: 0 (stdin) , 1 (stdout) , 2 (stderr) .
stdout — Стандартный вывод. Сюда попадает все что выводят программы
stdin — Стандартный ввод. Это все что набирает юзер в консоли
stderr — Стандартный вывод ошибок.
Для операций с этими дескрипторами, существуют специальные символы: > (перенаправление вывода), (перенаправление ввода). Оперировать ими не сложно. Например:

Если есть необходимость дописывать в файл(при использовании " > " он заменятеся), необходимо вместо " > " использовать " >> "

после просьбы sudo ввести пароль, он возьмется из файла my_password, как будто вы его ввели с клавиатуры.
Если необходимо записать в файл только ошибки, которые могли возникнуть при работе программы, то можно использовать:

цифра 2 перед " > " означает что нужно перенаправлять все что попадет в дескриптор 2(stderr).
Если необходимо заставить stderr писать в stdout , то это можно след. образом:

символ " & " означает указатель на дескриптор 1(stdout)
(Поумолчанию stderr пишет на ту консоль, в котрой работает пользователь(вренее пишет на дисплей)).

Конвеер — очень мощный инструмент для работы с консолью Bash. Синтаксис простой:
команда1 | команда 2 — означает, что вывод команды 1 передастся на ввод команде 2
Конвееры можно группировать в цепочки и выводить с помощью перенаправления в файл, например:

вывод команды ls -la передается команде grep , которая отбирает все строки, в которых встретится слово hash, и передает команде сортировке sort , которая пишет результат в файл sorting_list. Все довольно понятно и просто.

Чаще всего скрипты на Bash используются в качестве автоматизации каких-то рутинных операций в консоли, отсюда иногда возникает необходимость в обработке stdout одной команды и передача на stdin другой команде, при этом результат выполнения одной команды должен быть неким образом обработан. В этом разделе я постораюсь объяснить основные принципы работы с внешними командами внутри скрипта. Думаю что примеров я привел достаточно и можно теперь писать только основные моменты.

1. Передача вывода в переменную.

Для того чтобы записать в переменную вывод какой-либо команды, достаточно заключить команду в `` ковычки, например

Результат работы: qwerty

Однако если вы захотите записать в переменную список директорий, то необходимо, должным образом обработать результат для помещения данных в переменную. Рассмотрим небольшой, пример:

Здесь мы используем цикл for-do-done для архивирование всех директорий в папке /svn/ с помощью команды svnadmin hotcopy (что в нашем случае не имеет никого значения, просто как пример). Наибольшй интерес вызывает строка: LIST= find /svn/ -type d 2>/dev/null| awk ' '| sort|uniq | tr '\n' ' ' В ней переменной LIST присваивается выполнение команды find, обработанной командами awk, sort, uniq,tr(все эти команды мы рассматривать не будем, ибо это отдельная статья). В переменной LIST будут имена всех каталогов в папке /svn/ пгомещенных в одну строку(для того чтобы её стравить циклу.

предлагает 1-строчный метод для выключения долговременной команды из командной строки bash:

Но возможно, что заданная команда "long-running" может завершиться раньше таймаута. (Позвольте называть его командой "обычно долгое время, но иногда-быстро", или tlrbsf для удовольствия.)

Таким образом, этот отличный подход с 1 линейкой имеет несколько проблем. Во-первых, sleep не является условным, поэтому задает нежелательную нижнюю границу времени, затрачиваемого на завершение последовательности. Рассмотрите 30 секунд или 2 м или даже 5 м для сна, когда команда tlrbsf закончится через 2 секунды; крайне нежелательно. Во-вторых, kill является безусловным, поэтому эта последовательность будет пытаться убить нерабочий процесс и скулить об этом.

Есть ли способ отключить команду "tlrbsf" с типичным временем, но иногда - быстротой, которая

  • имеет реализацию bash (у другого вопроса уже есть ответы Perl и C)
  • завершается в начале двух: завершение программы tlrbsf или истечение времени ожидания
  • не будет убивать несуществующие/неработающие процессы (или, необязательно: не будет жаловаться на плохое убийство)
  • не должен быть 1-лайнером
  • может работать под Cygwin или Linux

. и для бонусных очков запускает команду tlrbsf на переднем плане и любой "спящий" или дополнительный процесс в фоновом режиме, так что stdin/stdout/stderr команды tlrbsf может быть перенаправлен так же, как если бы он был запущен напрямую?

Если да, делитесь своим кодом. Если нет, объясните, почему.

Я потратил некоторое время, пытаясь взломать вышеупомянутый пример, но я нажимаю предел своих навыков bash.

ОТВЕТЫ

Ответ 1

Я думаю, что это именно то, о чем вы просите:

Ответ 2

Вероятно, вы ищете команду timeout в coreutils. Так как это часть coreutils, это технически решение C, но оно все еще является ключевым. info timeout для более подробной информации. Вот пример:

Ответ 3

Это решение работает независимо от режима мониторинга bash. Вы можете использовать правильный сигнал для завершения вашей команды

Наблюдатель убивает вашу команду после заданного таймаута; script ждет медленную задачу и завершает наблюдателя. Обратите внимание, что wait не работает с процессами, которые являются дочерними элементами другой оболочки.

Примеры:

  • your_command запускается более 2 секунд и завершается
  • Ваша команда закончилась до таймаута (20 секунд)

Ответ 4

Я предпочитаю "timelimit", у которого есть пакет, по крайней мере, в debian.

Это немного лучше, чем тайм-аут coreutils, потому что он печатает что-то при убийстве процесса, а также по умолчанию отправляет SIGKILL.

Ответ 5

Ответ 6

Вы можете сделать это полностью с помощью bash 4.3 и выше:

  • Пример: _timeout 5 longrunning_command args
  • Пример: < _timeout 5 producer || echo KABOOM $?; >| consumer
  • Пример: producer |

Требуется Bash 4.3 для wait -n

Если вам не нужен код возврата, это можно сделать еще проще:

Строго говоря, вам не нужен ; в ; ) , однако он делает вещи более согласованными с ; > -case. И set +b , вероятно, тоже может быть оставлен, но лучше безопасен, чем сожалеть.

За исключением --forground (возможно) вы можете реализовать все варианты timeout . --preserve-status немного сложнее. Это остается как упражнение для читателя;)

Этот рецепт можно использовать "естественно" в оболочке (так же естественно, как и для flock fd ):

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

Пример реального мира: Time out __git_ps1 , если он занимает слишком много времени (для таких вещей, как медленные SSHFS-ссылки):

Edit2: Исправление ошибок. Я заметил, что exit 137 не требуется и делает _timeout ненадежным в одно и то же время.

Edit3: git - это умение, поэтому для работы нужно выполнить двойной трюк.

Edit4: Забыл a _ в первом _timeout для реального мира GIT example.

Ответ 7

вы можете изменить SIGINT и 10 по своему желанию;)

Ответ 8

На самом деле, я думаю, вы можете отменить его, выполнив свои "бонусные" критерии:

Ответ 9

Тайм-аут, вероятно, является первым подходом к попытке. Возможно, вам понадобится уведомление или другая команда для выполнения, если время истекает. После довольно многого поиска и экспериментов я придумал этот bash script:

Ответ 10

Если вы уже знаете имя программы (пусть предположим program ) завершаться после таймаута (в качестве примера 3 секунд), я могу внести простое и несколько грязное альтернативное решение:

Это работает отлично, если я вызываю тестовые процессы с системными вызовами.

Ответ 11

Там также cratimeout Мартин Крокауэр (написан на C для Unix и Linux систем).

Ответ 12

OS X не использует bash 4 и не имеет /usr/bin/timeout, поэтому здесь функция, работающая на OS X без home- brew или macports, которая похожа на /usr/bin/timeout (на основе ответа Tino). Вариация параметров, помощь, использование и поддержка других сигналов - упражнение для читателя.

Ответ 13

Простой script с ясностью кода. Сохранить в /usr/local/bin/run :

Временная команда, выполняемая слишком долго:

Заканчивается немедленно для команды, которая завершается:

Ответ 14

В 99% случаев ответ НЕ должен выполнять любую логику тайм-аута. Логика тайм-аута почти в любой ситуации является красным предупреждающим знаком о том, что что-то еще не так и должно быть исправлено.

Разве ваш процесс висит или ломается через несколько секунд? Затем выясните, зачем и зачем это исправлять.

Как и в стороне, для правильного решения строгана вам нужно использовать wait "$ SPID" вместо fg 1, поскольку в скриптах у вас нет управления заданиями (и попытка включить его глупо). Кроме того, fg 1 полагается на то, что вы ранее не запускали какие-либо другие задания в script, которые являются плохими предположениями.

Ответ 15

Ответ 16

Мне было предложено сохранить контекст оболочки и разрешить таймауты, единственная проблема с ней - это остановить выполнение script в таймаут - но это прекрасно с учетом потребностей, которые я представил:

конечно, я предполагаю, что существует dir, называемый scripts

Ответ 17

Моя проблема была немного иной: я запускаю команду через ssh на удаленном компьютере и хочу убить оболочку и дочерние элементы, если команда зависает.

Теперь я использую следующее:

Таким образом, команда возвращает 255, когда был достигнут тайм-аут или код возврата команды в случае успеха

Обратите внимание, что процессы убийства из сеанса ssh обрабатываются иначе, чем интерактивная оболочка. Но вы также можете использовать параметр -t для ssh для распределения псевдотерминала, поэтому он действует как интерактивная оболочка

Ответ 18

Вот версия, которая не полагается на порождение дочернего процесса - мне нужен автономный script, который встроил эту функцию. Он также выполняет фракционный интервал опроса, поэтому вы можете быстрее опроса. время ожидания было бы предпочтительным - но я застрял на старом сервере

Ответ 19

с pkill (опция -f) вы можете убить свою конкретную команду с помощью аргументов или указать -n, чтобы избежать уничтожения старого процесса.

Правильно ли запускать bash-скрипт с такой задержкой?



Конечно же неправильно. Независимо от целей и архитектуры системы. Или вы рассчитывали на другой ответ?

@klopp, можете объяснить почему неправильно? И как в таком случае запускать скрипт с задержкой в 0.5 секунд?

Если у вас возникает желание запускать некий скрипт с таким интервалом, что-то у вас неправильно на уровень повыше. Или, скорей, уровней на побольше, намного побольше. Начиная с постановки глобзадачи и спускаясь по реализации её подзадач.

Ну, всё бывет в первый раз. Подумайте хотя бы о том, какой счёт выставит участник аукциона ВАМ, если что-то случится по дороге от него до вашего скрипта. У него там мильон поставлен, а у вас задержка не 0.5, а 0.52 случилась.

2 ответа 2

Вот ожидание следующих 0.02 секунд можно доверить сну.

Если аукцион и бот выполняются на разных серверах, хорошо бы как-то синхронизировать часы с ними с большой точностью – может, сделав собственную реализацию подобия NTP.

в операционной системе gnu/linux реализация программы /bin/sleep , в дополнение к требованиям стандарта posix, поддерживает не только целочисленный аргумент, но и числа с плавающей точкой.

так что выбор за программистом: ориентироваться на posix-совместимость или на gnu-совместимость.


Всё ещё ищете ответ? Посмотрите другие вопросы с метками bash или задайте свой вопрос.

Похожие

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

дизайн сайта / логотип © 2022 Stack Exchange Inc; материалы пользователей предоставляются на условиях лицензии cc by-sa. rev 2022.1.24.41249

Иногда нужно приостановить вывод в скрипте, чтобы обратить внимание пользователя на информацию и убедиться, что пользователь увидел её (или имел возможность её увидеть).

В Bash это можно сделать с помощью утилиты read. Эта утилита читает строку из стандартного ввода.


Эта команда позволит пользователю продвинуться далее (а скрипт продолжит выполнение) после того, как пользователь нажмёт кнопку ENTER.

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


В этой команде следующее значение опций:

-n определяет количество символов, после которого будет остановлено чтение. По умолчанию чтение останавливается при вводе разделителя строк (например, кнопкой ENTER). В нашем случае команда read перестаёт считывать вводимые данные после первого символа

-s скрывает пользовательский ввод

Читайте также: