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

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

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

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

8 ответов

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

$ command1 &
$ wait; command2 &
$ wait; command3 &
$ ...

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 ограничен однобуквенными именами очереди.

Решения Брэда и Манкова являются хорошими предложениями. Другой вариант, похожий на их комбинацию, заключается в использовании 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"

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

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

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

  2. На компьютере, с которого вы перемещаете файлы (далее называемый исходным компьютером), установите rsync с apt-get install rsync и Task Spooler с секретным соусом (веб-сайт http://vicerveza.homeunix.net/~viric/soft/ts/). Если вы используете Debian, имя пакета для ts является 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.

Мне тоже часто нужны такие вещи. Я написал небольшую утилиту под названием 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 ...

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

Command1 && Command2

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

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

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

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

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

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

Другие вопросы по тегам