Вопрос или проблема
При попытке получить PID оболочки команды это возможно с помощью скрипта:
#!/bin/bash
ls -lha &
echo "$!"
Однако это невозможно использовать только терминал.
/bin/bash -c 'ls -lha & ; echo "$!"'
Это приводит к ошибке:
/bin/bash: -c: строка 1: синтаксическая ошибка рядом с неожиданным токеном `;’
Руководство гласит следующее:
Список — это последовательность из одной или нескольких конвейеров, разделенных одним из операторов
;
,&
,&&
или||
, и по желанию заканчивается одним из;
,&
или<новая строка>
.
Из этих операторов списков&&
и||
имеют равный приоритет, за ними следуют;
и&
, которые тоже имеют равный приоритет.Последовательность из одной или нескольких новых строк может появляться в списке вместо точки с запятой для разделения команд.
Если команда заканчивается оператором управления
&
, оболочка выполняет команду в фоновом режиме в подсистеме.
Оболочка не ждет завершения команды, и возвращаемый статус равен 0.
Команды, разделенные;
, выполняются последовательно; оболочка ждет завершения каждой команды по очереди.
Возвращаемый статус — это выходной статус последней выполненной команды.
Я также пытался использовать новую строку, но не смог сделать это:
/bin/bash -c 'ls -lha & \n echo "$!"'
Как я могу вызвать команду оболочки для выполнения в фоновом режиме и получить PID?
П.С.: Я не буду использовать команду ls
, это более сложный скрипт.
Это всего лишь минимальный пример, чтобы воспроизвести проблему.
И ;
, и &
являются разделителями команд.
Вам нужен один, чтобы отделить команду ls
от команды echo
, но не оба.
Просто уберите ;
и сделайте
/bin/bash -c 'ls -lha & echo "$!"'
Если хотите, можете добавить реальную новую строку:
/bin/bash -c 'ls -lha &
echo "$!"'
или используйте $'…'
:
/bin/bash -c $'ls -lha & \n echo "$!"'
Конечно, вам нужно иметь разделители команд между командами; один между каждыми двумя последовательными командами.
Так что, если вы хотите, скажем, четыре команды, где первая асинхронная, а остальные синхронные, вам нужно использовать
команда1 & команда2; команда3; команда4
Ответ или решение
Для получения PID (идентификатора процесса) команды в одной строке Bash-скрипта, необходимо правильно использовать оператор &
для запуска команды в фоновом режиме и обеспечить корректное использование разделителей команд. Основная проблема, связанная с ошибкой синтаксиса, возникает из-за неправильного размещения операторов.
Решение проблемы
Для запуска команды и получения её PID в одной строке вы можете использовать следующий вариант:
/bin/bash -c 'ls -lha & echo "$!"'
Эта строка работает следующим образом:
ls -lha &
– запускает командуls -lha
в фоновом режиме. Оператор&
сообщает оболочке, что команда должна быть выполнена в фоне.echo "$!"
– выводит PID последнего запущенного фонового процесса. Переменная$!
содержит идентификатор процесса последней команды, выполненной в фоновом режиме.
Альтернативные способы
Если вы предпочитаете использовать новую строку, то в качестве разделителя можно использовать следующий подход:
/bin/bash -c 'ls -lha &
echo "$!"'
Либо, используя формат $'...'
, который позволяет явно включать управляющие символы, такие как новая строка:
/bin/bash -c $'ls -lha &\necho "$!"'
Применение в более сложных скриптах
Если ваш скрипт включает в себя большее количество команд, где одна из них выполняется асинхронно, вы можете организовать код следующим образом:
command_1 & command_2; command_3; command_4
Где command_1
выполняется в фоновом режиме, а command_2
, command_3
и command_4
выполняются последовательно, дожидаясь завершения предыдущей команды.
Заключение
Важно понимать, что правильное использование разделителей команд и работу с фоновыми процессами необходимо для успешного выполнения задач в Bash. Приведенные решения позволяют вам легко получать PID команды, запущенной в фоновом режиме, и будут работать для различных сценариев выполнения более сложных скриптов.