Как запускать команды как в очереди
Мне нужно много копировать разные файлы в разные папки. Я могу добавить все свои команды копирования в скрипт 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, а остальные - на новую машину.
Вот как я это сделал.
Настройте все машины, подключенные к сетевому соединению, чтобы они могли связаться друг с другом.
На компьютере, с которого вы перемещаете файлы (далее называемый исходным компьютером), установите 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
или похожие.Также убедитесь, что на всех машинах установлен 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
(при условии, что соединение использует одно и то же целевое имя хоста и порт).На этом этапе вам необходимо убедиться, что вы можете войти в систему без запроса аутентификации на целевых машинах.
Теперь беги
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.