Как использовать / отправлять сигналы в командной строке для любой программы (например, dd)

Как использовать / отправлять сигналы в командной строке для любой программы (например, dd)

Я пытаюсь понять страницу руководства ddпрограммы, в которой упоминается:

Отправка сигнала USR1 запущенному процессу «dd» заставляет его выводить статистику ввода-вывода в стандартный поток ошибок, а затем возобновлять копирование.

         $ dd if=/dev/zero of=/dev/null& pid=$!
         $ kill -USR1 $pid; sleep 1; kill $pid

Что pid=$!значит?

Это присвоение переменной, которая получает pid dd? И в конечном итоге используется в $pidпеременной?

И почему они используют sleepи kill?

Это способ использования -USR1?

решение1

dd if=/dev/zero of=/dev/null&

Конечный символ &означает запуск команды префикса в фоновом режиме. (Отказ от ответственности: это слишком упрощенное утверждение)

Ссылаться наэтот:

$! — это PID последней фоновой команды.

Итак, pid=$!назначьтеСамый последний фоновый PIDк переменной pid, которая является ddPID.

И почему они используют сон и убийство?

Тебе нужноkill $pid (если параметр не указан, сигналом по умолчанию для kill является TERM, что означает завершение процесса)чтобы завершить ddпроцесс после завершения тестирования, в противном случае ddпроцесс может просто остаться в фоновом режиме и истощить ресурсы вашего процессора. Проверьте ваш системный монитор вашей платформы, чтобы увидеть.

При Kill -USR1 $pidпечати статистики ввода-вывода процесс не завершается.

Без сна в 1 секунду ваш ddпроцесс может быть завершен последним оператором команды kill $pid** до того, как появится возможность записать вывод статистики на ваш терминал. Процессы синхронны, нооперация ловушка+запись( kill -USR1 $pid) может быть медленнее, чемзавершить операцию( kill $pid). Поэтому sleep 1во-вторых, отложите запуск, kill $pidчтобы гарантировать, что вывод статистики будет выполнен.

Вот как использовать -USR1?

Только man dd:

Отправка сигнала USR1 запущенному процессу «dd» заставляет его выводить статистику ввода-вывода в стандартный поток ошибок, а затем возобновлять копирование.

И man 7 signal:

   SIGUSR1   30,10,16    Term    User-defined signal 1
   SIGUSR2   31,12,17    Term    User-defined signal 2

Объедините оба утверждения, и вы поймете, что USR1 — этоСигнал, определяемый пользователемкоторый определяется как ddпредоставление пользователю возможности прервать его ираспечатать статистику ввода-выводана лету. Это обработчик, специфичный для программы, это не значит, что вы можете kill -USR1 other_program_pidожидать вывода статистики.

Также вас может заинтересовать информация оэто: Почему SIGUSR1 приводит к завершению процесса?.

решение2

Это всего лишь демонстрация, иллюстрирующая использование USR1сигнала dd.

dd if=/dev/zero of=/dev/null &

запускается ddв фоновом режиме, копируя данные из /dev/zero(который выдает нули всякий раз, когда программа читает из него) в /dev/null(который отбрасывает все, что в него записано). Это обеспечивает безвредный экземпляр, с ddкоторым можно экспериментировать — он не использует память и будет работать столько, сколько мы захотим, что дает пользователю время отправлять ему сигналы.

pid=$!

сохраняет идентификатор процесса последней фоновой команды ( $!) в переменной pid.

kill -USR1 $pid

посылает USR1сигнал процессу, идентификатор которого — значение, сохраненное в переменной, в данном случае pidфон . Получив этот сигнал, он выводит свой текущий прогресс (объем прочитанных и записанных данных) и продолжает копирование.dddd

sleep 1

ждет одну секунду.

kill $pid

посылает TERMсигнал dd, что приводит ddк выходу. (Нет смысла оставлять фоновый процесс ddзапущенным здесь.)

Было бы более поучительно запустить это вместо второй строки выше:

kill -USR1 $pid; sleep 1; kill -USR1 $pid; kill $pid

Это выведет прогресс дважды с интервалом в одну секунду, чтобы показать ddпрогресс; затем завершит работу ddбез ожидания.

Для фактического использования вам нужно будет указать соответствующие входные и выходные данные для исходной ddкоманды, а также, возможно, некоторые другие параметры, и вы не будете запускать последнюю kill— вы будете ждать ddее завершения самостоятельно.

Чтобы ответить на ваш последний вопрос, вот как вы посылаете USR1сигналы из оболочки (или любой другой сигнал): вы используетеkillс сигналом, который вы хотите отправить, и идентификаторами процесса (или идентификаторами задания) процессов, которым вы хотите отправить сигнал. Другие (не POSIX) команды, которые вы можете использовать, этоpkillиkillall, когда вы хотите найти процессы по имени.

решение3

Для большинства или всех оболочек $!— это идентификатор процесса (также называемый PID) последнего процесса, который оболочка разветвила. Команда ddразветвилась с помощью &, так что справа pid=$!после разветвления ddназначается ddидентификатор процесса переменной оболочки pid.

Идентификатор процесса — это число, используемое Linux или Unix для обозначения адресного пространства, в котором выполняется некоторый код.

Программа killимеет неинтуитивное название, потому что ее цель — отправлять сигналы (небольшие, асинхронные сообщения) процессам. Есть только несколько сигналов, может быть, 128 в общей сложности, они имеют и номера, и имена. Сигнал «kill» имеет номер 9, например. USR1 определяется как номер 10. Таким образом, отправляет kill -USR1 $pidсигнал 10 процессу с номером $pid. ddиногда требуется много времени для выполнения, так что это почти наверняка идентификатор процесса команды, ddкоторая была разветвлена ​​ранее и запущена в фоновом режиме. kill $pidКоманда отправляет сигнал TERM тому же идентификатору процесса. TERM означает «завершить». Хорошо написанные программы обычно перехватывают TERM, очищают выделенные им ресурсы и затем выходят.

Я не совсем уверен, почему вы работаете ddв фоновом режиме, отправляете ему сигнал USR1, ждете 1 секунду, а затем вызываете ddосвобождение всех ресурсов и выход. Весь фрагмент кода, похоже, предполагает, что ddон выполняется долгое время, что может быть не так. Я думаю, что в этом коде есть состояния гонки, и какой бы ни была желаемая семантика, вы можете их не получить.

решение4

Если вы ожидаете, ddчто команда будет запущена в фоновом режиме и отобразит текущий статус выполнения, попробуйте запустить команду с status=progressфлагом:

sudo dd if=/dev/sda of=/dev/sdb status=progress

Это позволит динамически отображать ход выполнения.

Это расширение реализации GNU dd(добавлено в версии 8.24, выпущенной в 2015 году), также доступное в ddреализации FreeBSD с версии 12.0 (2018), но, как правило, недоступное в других реализациях, в том числе в других BSD.

Связанный контент