2013-12-13 6 views
5

У меня проблема с проверкой того, действительно ли какая-то команда в цепочке команд с несколькими трубами выбрасывает ошибку. Обычно это не сложно проверить, но ни set -o pipefail, ни проверка ${PIPESTATUS[@]} работает в моем случае. Настройка такова:Bash: проверка состояния выхода для многотрубной цепочки команд

cmd="$snmpcmd $snmpargs $agent $oid | grep <grepoptions> for_stuff | cut -d',' f$fields | sed 's/ubstitute/some_other_stuff/g'" 

Примечание: 1 команда была проверена полностью и отлично работает.

Теперь я хочу сохранить вывод этой команды в массиве с именем procdata. Таким образом, я сделал:

declare -a procdata 
procdata=($(eval $cmd)) 

Note-2: eval необходимо, потому что в противном случае $snmpcmd подбрасывает с invalid option -- <grepoption> ошибкой, которая не имеет никакого смысла, потому что <grepoption> не является $snmpcmd вариант, очевидно. На этом этапе я считаю ошибку ошибкой с $snmpcmd, но это еще одно шоу ...

При возникновении ошибки procdata будет пустым. Однако он может быть пустым по двум причинам: либо из-за ошибки при выполнении $snmpcmd (например, таймаута), либо потому, что grep не смог найти то, что искал. Проблема в том, что мне нужно иметь возможность различать эти два случая и обрабатывать их отдельно.

Таким образом, set -o pipefail не является вариантом, так как он будет распространять любую ошибку, и я не могу различить, какая часть трубы не удалась. С другой стороны, echo ${PIPESTATUS[@]} всегда 0 после procdata=($(eval $cmd)), хотя у меня много труб!?. Тем не менее, если я выполняю всю команду непосредственно в приглашении и сразу вызываю echo ${PIPESTATUS[@]}, он правильно возвращает статус выхода всех каналов.

Я знаю, что могу связать поток err с stdout, но мне нужно будет использовать эвристические методы, чтобы проверить, являются ли элементы в procdata действительными или сообщениями об ошибках, и я рискую получить ложные срабатывания. Я мог бы также вывести stdout на /dev/null и захватить только поток ошибок и проверить, ${#procdata[@]} -eq 0. Но мне пришлось бы повторить звонок, чтобы получить фактические данные, и вся команда будет дорогостоящей (около 3-5 секунд). Я бы не хотел называть это дважды. Или я мог бы использовать временный файл для записи ошибок, но я бы предпочел сделать это без накладных расходов на создание/удаление файлов.

Любые идеи, как я могу сделать эту работу в bash?

Благодаря

PS:

$ echo $BASH_VERSION 
4.2.37(1)-release 

ответ

3

ряд вещей здесь:

(1) Когда вы говорите eval $cmd и попытаться получить значение выхода из процессов в трубопроводе, содержащемся в команда $cmd, echo "${PIPESTATUS[@]}" будет содержать только статус выхода для eval. Вместо eval вам нужно будет предоставить полную командную строку.

(2) Вам нужно получить PIPESTATUS при назначении вывода конвейера переменной. Попытка сделать это позже не сработает.


В качестве примера, вы можете сказать:

foo=$(command | grep something | command2; echo "${PIPESTATUS[@]})" 

Это перехватывает вывод трубопровода и PIPESTATUS массив в переменной foo.

Вы можете получить вывод команды в массив, говоря:

result=($(head -n -1 <<< "$foo")) 

и PIPESTATUS массив, говоря

tail -1 <<< "$foo" 
+0

Я была такая же мысль. К сожалению, это тоже не работает, но я не знаю, почему. Я отправляю точные команды, потому что я не вижу очевидного: – user3040975

+0

'local cmdargs =" - CHf, -m $ mibs -v $ snmpver -c $ community $ agent "; local procdatacmd = "$ tblcmd $ cmdargs $ proc_table"; procdatacmd + = "| cut -d ',' -f $ fields | grep -we -e | sort | uniq -c | sed 's/^ * \ | \" // g; s//,/g' ; echo $ {PIPESTATUS [@]} "'. Тогда я делаю: 'declare -a procdata = ($ (head -n -1 <<< $ procdatacmd))'. Выход пуст ... просто ничего. и ... – user3040975

+0

@ user3040975 Вы не являетесь _running_ любой командой в строке выше. – devnull

 Смежные вопросы

  • Нет связанных вопросов^_^