Я пытаюсь проверить количество запущенных и поставленных в очередь заданий PBS, анализируя вывод qstat -tn1
из bash
скрипта. Пока это сработало:
count ()
{
qstat -tn1 | awk '
BEGIN { R = 0; Q = 0; }
$10 == "R" { R++ }
$10 == "Q" { Q++ }
END { print R, Q }'
}
if read -r R Q < <(count)
...
Однако я вижу, что qstat
иногда это не удается по неизвестным причинам. В этом случае он ничего не печатает в stdout
и какое-то сообщение об ошибке в stderr
и завершается с ненулевым статусом (довольно стандартно). Однако awk
не знает, что qstat
произошел сбой, и с радостью печатает 0 0
для пустого ввода, который он получил. Затем read
присваивает 0 обоим R
и Q
не зная, что qstat
на самом деле произошел сбой.
- Мне нужно инициализировать
R
иQ
значением 0 вBEGIN
блоке скриптаawk
, поскольку может не быть запущенных процессов или процессов в очереди, и мне нужно вывести0
, а не просто пустую строку, количество таких процессов. - Я мог бы сделать это
set -o pipefail
, что позволило быcount
выйти с ненулевым статусом, ноread
не смог бы увидеть статус выхода и в любом случаеawk
был бы выполнен и выведен на экран0 0
для пустого ввода. - Я мог бы попробовать именованный канал и подпроцессы, но необходимость управлять ими кажется мне излишеством и слишком сложным.
Есть ли хороший способ позволить вызывающему объекту count
обнаружить его сбой?
решение1
Я думаю, что чтение count
в подстановке процесса не позволяет вам получить его статус возврата. Так что не делайте этого. Вместо этого сохраните результат в переменной или используйте канал.
count=$(count)
if [ $? -eq 0 ]; then
read -r R Q <<<"$count"
…
или
set -o pipefail
if count | { read -r R Q; … }
Другая возможность — использовать PIPESTATUS
переменную для проверки статуса возврата первой команды.
count=$(qstat -tn1 | awk …)
if ((${PIPESTATUS[0]} == 0)); then
read P Q
…
В качестве альтернативы можно настроить awk так, чтобы он выводил что-то отличительное (например, ничего), когда его входные данные пусты.
awk '
BEGIN { R = 0; Q = 0; }
$10 == "R" { R++ }
$10 == "Q" { Q++ }
END { if (NR) print R, Q }'
Вы можете проверить, является ли ввод команды пустым, с помощью ifne
frommoreutilsилидругие методы. Но поскольку вы подключаетесь к awk, вы могли бы сделать это прямо внутри скрипта awk, который у вас уже есть.
Если вам нужно получить статус возврата от qstat
команды, вы можете передать его awk как дополнительную строку ввода. Для облегчения разбора сделайте так, чтобы последняя строка имела уникальный формат.
{
qstat -tn1
echo exit_code = $?
} | awk '
…
/^exit_code = / { status = $3 }
END { if (status == 0) print Q, R }
'
решение2
Этот:
count ()
{
{ qstat -tn1 || echo "EPIC FAIL" } | awk '
BEGIN { R = 0; Q = 0; }
$10 == "R" { R++ }
$10 == "Q" { Q++ }
END { print R, Q }'
}
if read -r R Q < <(count)
...
В случае qstat
успеха его вывод отправляется в awk
. Если qstat
возвращается ненулевой статус, текст «EPIC FAIL» отправляется в awk
.
Это всего лишь пример. Замените эхо чем-то подходящим, что вы можете обработать внутри awk
или с помощью if read
.