Как запускать команды как в очереди

35322
Svish

Мне нужно много копировать разные файлы в разные папки. Я могу добавить все свои команды копирования в скрипт bash и затем запустить его, но затем я должен дождаться его завершения, если я хочу добавить больше команд в эту «очередь» копирования.

Есть ли способ, с помощью которого я могу запускать команды в виде очереди и как бы добавлять команды в эту очередь во время работы?

Объясненный по-другому, я хочу начать долгосрочную задачу. Пока он работает, я хочу запустить еще один, который на самом деле не запускается, пока не будет сделан первый. А затем добавить еще один после этого последнего и так далее. Это возможно как-то?

37
Могу ли я предложить вам принять ответ, который решает вашу проблему. Кажется, есть пара из них, которые будут работать для вас. holmb 11 лет назад 3
Да, вы можете, и я хотел. Проблема в том, что я спросил об этом, когда работал в компании, которая использовала Mac. Я там больше не работаю, и у меня нет компьютеров Mac, поэтому я не могу протестировать ни один из них. Не чувствую себя комфортно, отмечая один ответом, когда я не могу проверить, действительно ли он работает, поэтому сейчас я надеялся, что люди проголосуют за те ответы, которые они считают подходящими для них, чтобы «ответ» мог появиться таким образом. вместо. Svish 11 лет назад 2

8 ответов на вопрос

23
Gilles

atУтилита, самая известная для запуска команд в заданное время, также имеет функцию очереди и может быть предложена для запуска команды в настоящее время. Он читает команду для запуска со стандартного ввода.

echo 'command1 --option arg1 arg2' | at -q myqueue now echo 'command2 ...' | at -q myqueue now 

Команда batchэквивалентна at -q b -m now( -mимеется в виду, что выходные данные команды, если таковые имеются, будут отправлены вам по почте, как это делает cron). Не все варианты Unix поддерживают имена очередей ( -q myqueue); Вы можете быть ограничены одной вызванной очередью b. Linux atограничен однобуквенными именами очередей.

В Linux, по крайней мере, это, кажется, не ждет завершения предыдущей команды. wds 9 лет назад 2
@wds работает для меня на Debian wheezy. Где и как это сломалось для вас? Обратите внимание, что at ожидает только завершения команды; если команда запускает подпроцессы, которые переживают своего родителя, at не ожидает подпроцессов. Gilles 9 лет назад 0
Я попробовал на CentOS 6. Я тестировал с простым "sleep x". Я не уверен, что at делает, чтобы запустить это, но я предполагаю, что он запускает подоболочку, и эта подоболочка должна ждать результата (спящий вызов не возвращается сразу). wds 9 лет назад 0
Как и имена очередей, «сейчас» также не выглядит стандартным: bash на Ubuntu жалуется на это ... winwaed 8 лет назад 0
@winwaed О, это `сейчас`, а не` -т сейчас`, извините. Я не заметил, что это неправильно в примере кода. Gilles 8 лет назад 0
@ Жиль: быстрый ответ на старую ветку. В конце концов я реализовал обходной путь Python для того, что хотел, но могу вернуться к этому, если это окажется трудной задачей в тестировании! (Bash, вызывающий Python, вызывает Bash, может быть чище ...) winwaed 8 лет назад 0
Кажется, что он не соответствует порядку очереди ... Michael 6 лет назад 0
21
Vortico

Добавьте &в конец свою команду, чтобы отправить ее в фоновый режим, а затем waitна нее, прежде чем запускать следующую. Например:

$ command1 & $ wait; command2 & $ wait; command3 & $ ... 
ура! этот синтаксис великолепен, когда вы что-то запускаете, а затем смотрите на stackoverflow, чтобы найти способ поставить что-то в очередь после него Erik Aronesty 11 лет назад 2
Если вы передумаете над какой-либо из этих команд, что можно сделать, чтобы прервать `wait`? Это кажется непроницаемым для всех моих убийств. Ken Williams 11 лет назад 2
Вы просто убиваете команду. `Wait` просто останавливает работу до завершения предыдущих. Gert Sønderby 9 лет назад 1
Будет ли это работать с `nohup`? Michael 6 лет назад 0
11
Jordan

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

Первый забег:

$ screen -d -m -S queue 

(кстати, сейчас самое время поиграть с некоторыми классными файлами screenrc ).

Это вызовет сеанс фонового экрана для вас с именем queue.

Теперь поставьте в очередь столько команд, сколько хотите:

screen -S queue -X stuff "echo first; sleep 4; echo second^M" 

Я делаю несколько команд в приведенном выше только для тестирования. Ваш вариант использования будет выглядеть примерно так:

screen -S queue -X stuff "echo first^M" screen -S queue -X stuff "echo second^M" 

Обратите внимание, что «^ M» в моей строке выше - это способ получить встроенный символ новой строки, который будет интерпретирован позже после того, как экран вставит его в существующую оболочку bash. Используйте «CTL-V», чтобы получить эту последовательность.

Было бы довольно легко сделать несколько простых сценариев оболочки для автоматизации этого и поставить команды в очередь. Затем, всякий раз, когда вы хотите проверить состояние фоновой очереди, вы повторно присоединяете через:

screen -S queue -r 

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

Конечно, если вы сделаете это, другой хороший способ сделать это - назвать одну из текущих окон «очередь» и использовать:

screen -S queue -p queue -X stuff "command" 
Похоже, что это в основном просто «набирает» команду в сеансе рабочего экрана, поэтому, когда оболочка снова получает контроль после завершения первой команды, эта команда запускается. Другими словами, это эквивалентно решению @ mankoff, но для его набора используется более изящный инструмент. Ken Williams 11 лет назад 0
Довольно много - главное отличие в том, что экранное решение поддерживает лучшую автоматизацию. Вы можете делать некоторые вещи вручную, другие - с помощью скриптов, все с простым интерфейсом. Jordan 11 лет назад 0
7
holmb

Есть утилита, которую я использовал с большим успехом именно для описанного вами варианта использования. Недавно я перенес свой основной ноутбук на новое оборудование, которое включало перенос некоторых файлов на NAS, а остальные - на новую машину.

Вот как я это сделал.

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

  2. На компьютере, с которого вы перемещаете файлы (в дальнейшем называемом исходным компьютером), установите rsync apt-get install rsyncи Task Spooler с секретным соусом (веб-сайт http://vicerveza.homeunix.net/~viric/soft/ts/ ). Если вы используете Debian, имя пакета для tsis task-spoolerи исполняемый файл переименовываются, tspчтобы избежать конфликта имен с tsисполняемым файлом из moreutilsпакета. Пакет Debian, связанный с веб-сайтом, отлично устанавливается на Ubuntu dpkg -i task-spooler_0.7.3-1_amd64.debили аналогичном.

  3. Также убедитесь, что на всех машинах установлен SSH apt-get install openssh-server. На исходном компьютере необходимо настроить SSH, чтобы разрешить вход без пароля на целевые компьютеры. Чаще всего будет использоваться метод аутентификации с открытым ключом ssh-agent( примеры приведены в https://www.google.se/search?q=ssh+public+key+authentication ), но иногда я использую более простой метод, который работает просто а также с аутентификацией по паролю. Добавьте следующее в вашу конфигурацию клиента SSH ( ~/.ssh/configили /etc/ssh/ssh_config):

    Host * ControlMaster auto ControlPath ~/.ssh/master-%r@%h:%p 

    Затем откройте один терминал на исходном компьютере, войдите в систему ssh target1, выполните обычную аутентификацию и оставьте этот терминал открытым. Обратите внимание, что существует файл сокета с именем ~/.ssh/master-user@target1:22, это файл, который будет держать аутентифицированную основную сессию открытой и разрешать последующие соединения без пароля user(пока соединение использует одно и то же целевое имя хоста и порт).

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

  4. Теперь запустите ts rsync -ave ssh bigfile user@target1:для одного файла или ts rsync -ave ssh bigdir user@target1:для каталога. При использовании rsync важно не включать косую черту в каталог ( bigdirпо сравнению с bigdir/), иначе rsync будет предполагать, что вы имели в виду эквивалент bigdir/*большинства других инструментов.

    Диспетчер задач вернет приглашение и позволит вам поставить в очередь многие из этих команд подряд. Проверьте очередь выполнения tsбез аргументов.

Диспетчер задач имеет много функций, таких как перестановка очереди выполнения, запуск определенного задания только в случае успешного выполнения другого задания и т. Д. См. Справку ts -h. Иногда я проверяю вывод команды, пока он работает с ts -c.

Есть и другие способы сделать это, но для вашего случая использования они все включают диспетчер задач. Я решил использовать rsync поверх SSH для сохранения временных меток файлов, которых не было бы при копировании через SMB.

спасибо за ваш ответ, который я не знал о `ts ', он кажется очень мощным и простым в использовании, просто [разветвляется на github] (https://github.com/xenogenesi/task-spooler.git) с автоматическими инструментами и дебианизирован. Alex 9 лет назад 0
@ Алекс Я посмотрел на ваш форк и особенно интересовался тем, что было сделано в отношении автоинструмента и дебианизации исходного источника, и, глядя на ваши коммиты, он не был легко доступен в качестве diff для исходного источника. Не могли бы вы принудительно выдвинуть новые коммиты, которые на шаге 1. импортируют исходный код и 2. коммитят с вашими дополнениями? Это поможет кому-то просматривать ваш источник (легче) доверять вашим дополнениям к исходному источнику. Это один из немногих пакетов, которые я не устанавливаю из PPA или подобного, поэтому было бы неплохо собрать его самостоятельно с помощью своей вилки. holmb 9 лет назад 0
вы знаете, что я должен поменять очки, я потерял часть вашего ответа о существующем `task-spooler` :-) ... в любом случае, это в вашем комментарии очень хорошее предложение, я сделаю это очень скоро. Alex 9 лет назад 0
сделал, удалил и заново создал хранилище с прогрессивными коммитами, всего пара ошибок (перед тем как нажать push, нужно усвоить больше локальных коммитов) Alex 9 лет назад 0
4
Ken Williams

Мне тоже часто нужны такие вещи. Я написал небольшую утилиту под названием, afterкоторая выполняет команду всякий раз, когда завершается какой-то другой процесс. Это выглядит так:

#!/usr/bin/perl  my $pid = shift; die "Usage: $0 <pid> <command...>" unless $pid =~ /^\d+$/ && @ARGV;  print STDERR "Queueing process $$ after process $pid\n"; sleep 1 while -e "/proc/$pid"; exec @ARGV; 

Затем вы запускаете это так:

% command1 arg1 arg2 ... # creates pid=2853 % after 2853 command2 arg1 arg2 ... # creates pid=9564 % after 9564 command3 arg1 arg2 ... 

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

Хороший сценарий @ken. Хотя я бы порекомендовал попробовать Task Spooler, поскольку время от времени вам это требуется. Смотри мой ответ. holmb 11 лет назад 0
Выглядит аккуратно, спасибо. Кажется, единственное, чего не хватает в TS, - это возможность выполнять задания, которые не были запущены в TS. Хотя я думаю, что вы могли бы начать новую работу TS, цель которой - просто дождаться завершения существующего процесса. Ken Williams 11 лет назад 0
В самом деле. Это полезный аспект вашего решения. holmb 11 лет назад 0
1

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

Либо наберите внимательно, либо напечатайте в другом месте, проверьте и вырежьте и вставьте. Даже если текущая команда издает строки вывода, вы все равно можете набрать что-то новое, нажать клавишу ввода, и она запустится, когда все команды будут запущены или введены до ее завершения.

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

echo "foo" sleep 10; echo "bar" sleep 3 echo "baz" 
1
naftuli

Command1 && Command2

  • «&&» означает, что команда2 выполняется только после того, как команда1 завершается с кодом возврата 0
  • Примечание: a || означает, что команда2 выполняется только после того, как команда1 завершается с кодом возврата, отличным от 0
0
Brad Clawsie

самый хакерский способ, который я могу придумать, - это поддерживать состояние очереди с помощью простых файлов блокировки в / tmp. когда file1.sh выполняет свои команды cp, он сохраняет файл блокировки (или жесткую ссылку) в / tmp. когда это будет сделано, удалите файл. каждый другой скрипт должен искать в / tmp файлы блокировки с выбранной вами схемой именования. Естественно, это подвержено всевозможным сбоям, но настроить его тривиально и выполнимо полностью в bash.

Трудно использовать на практике, так как требует, чтобы каждое задание, которое вы хотите выполнить, было изменено для сохранения файлов блокировки, и ему нужно было знать (или принимать в качестве параметров) * какие * файлы блокировки использовать. Когда это возможно, лучше иметь очередь вне работы. Ken Williams 11 лет назад 0

Похожие вопросы