Возможно, это не тот ответ, который вы ищете, но простой Makefile, похоже, удовлетворит ваши требования. Завершите выполнение ошибки из-за ошибки, и ее цель состоит в том, чтобы избежать повторения шагов обработки. Особенно, если (по крайней мере, большинство) ваши команды генерируют выходной файл, это было бы довольно естественным образом. Если нет, сохранение простого файла состояния - это обычная Make idiom, чтобы отметить последовательность команд как успешно завершенную.
(Если вы новичок сделать, заметьте, что каждая команда в мишени должна иметь вкладку буквальную для отступа.)
.PHONY: all
all: .command1-done .command2-done
.command1-done:
command1
touch [email protected]
# Comment out the dependency to avoid forcing sequential execution
.command2-done: .command1-done
command2
touch [email protected]
.PHONY: clean
clean:
rm -f .*-done
Таким образом, это работает command1
и, в случае успеха, переходит к следующую команду в рецепте, которая запускает touch
в файле семафора (переменная Make [email protected]
расширяется до текущего целевого имени). Если это тоже удастся, он запускает command2
и аналогичным образом создает свой «готовый» файл, если он преуспевает. Бег make
снова покажет вам, что ни одна из команд не нужно запускать:
$ make
command1
touch .command1-done
command2
touch .command2-done
$ make
make: Nothing to be done for `all'.
Если вы на самом деле заботитесь о порядке выполнения целей, которые, как правило, потому, что существует зависимость (command2
выходит из строя или, что еще хуже, приведет к получению неверных результатов если он не запущен после command1
).Такие зависимости нужно объявить - я приведу пример того, как объявлять такие отношения. Если нет зависимости, вы, вероятно, не должны объявлять ее; то Make будет запускать ваши цели в произвольном порядке (хотя версии, с которыми я работал, обычно предсказуемы); или вы можете запустить их параллельно с make -j
.
(состояние файла обычно начинается с точки, чтобы держать его скрытые от обычного списка каталогов.)
Более реалистично, возможно, ваши команды на самом деле сгенерировать вывод:
.PHONY: all
all: grep.out wc.out
grep.out:
grep -Fw Debian /etc/motd >[email protected]
wc.out: grep.out
wc -l <$< >[email protected]
(К сожалению, . Shell перенаправление создаст выходной файл, даже если цель проваливает временное решение использовать временный выходной файл, а затем перенести его на место только на успех:
.PHONY: all
all: grep.out wc.out
grep.out:
grep -Fw Debian /etc/motd >[email protected]
mv [email protected] [email protected]
wc.out: grep.out
wc -l <$< >[email protected]
mv [email protected] [email protected]
.PHONY: clean
clean:
rm -f .*.tmp
Но так или иначе, это уже слишком длинное.)
Если вам действительно нужно отслеживать состояние * каждой команды * и повторное выполнение поддержки из любой произвольной точки, вам потребуется вручную записать каждый статус выхода файл и перед каждой строкой проверять, правильно ли работала команда на этой строке в последний раз (или создать временную копию сценария с удалёнными удаленными строками с помощью 'sed' или аналогичного). Но это звучит как неправильное решение для меня. В чем здесь проблема? (Что-то вроде 'make' действительно может быть полезным для этого потенциально также.) –
Это должно быть bash? Для этого я бы использовал perl. Конечно, мои perl skils лучше, чем bash, и я уверен, что есть bash, которые могут быть более полезными, но если вам нравится, я могу показать вас в perl. – terary
@ Этан Рейснер, любая реализация этого решения? У меня уже есть проверка кодов выхода команд. Я искал удобный способ вернуться к определенной функции. Мне нужно это для сценариев обновления/настройки, которые я хочу запустить на новых виртуальных машинах. – ton1c