38

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

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

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

8 ответов8

24

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

21

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

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

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

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

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

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

  2. На компьютере, с которого вы перемещаете файлы (далее - исходный компьютер), установите rsync с помощью apt-get install rsync и диспетчера задач с секретным соусом (веб-сайт 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.

4

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

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

1

Command1 && Command2

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

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

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

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

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

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

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