Захват SSH-выхода как переменной в bash script
Я столкнулся с этой проблемой при написании bash script.
В принципе, я хочу измерить время программы на удаленном сервере, поэтому я использую команду:
/usr/bin/time -f %e sh -c "my command > /dev/null 2>&1"
для выполнения программы.
Тем не менее, похоже, что я не могу полностью захватить вывод моей команды (SSH). Фактически, результат (время) продолжает печататься в стандартный вывод.
Полный код:
respond=$(ssh ${fromNode} /usr/bin/time "-f" "%e" "'sh' '-c' 'virsh migrate --live ${VM} qemu+ssh://${toNode}/system --verbose > /dev/null 2>&1'")
Значение ответа просто пуст, хотя время выводится на стандартный вывод.
Ответы
Ответ 1
Команда "time" выводит результат на stderr, а не на stdout. Таким образом, он не попадает в вашу переменную.
Вы должны перенаправить stderr в stdout для достижения того, что вы хотите:
result=$(ssh host time "command" 2>&1)
И ваш полный код может выглядеть примерно так:
respond=$(ssh ${fromNode} /usr/bin/time "-f" "%e" "'sh' '-c' 'virsh migrate --live ${VM} qemu+ssh://${toNode}/system > /dev/null 2>&1'" 2>&1)
Ответ 2
Попробуйте поменять порядок перенаправления (до 2>&1 >/dev/null
). Ваш текущий код отправляет как stdout, так и stderr в /dev/null (так что мне любопытно, почему что-то напечатано вообще).
Почему это необходимо? Синтаксис 2>&1
означает 'duplicate stdout (дескриптор 1) как stderr (дескриптор 2)'; по сути, stderr превращается в копию текущего stdout. Если сначала поставить >/dev/null
, то stdout сначала перенаправляется на /dev/null, а затем stderr указывается на текущий stdout, то есть /dev/null.
Но если вы поместите >/dev/null
second, stderr сначала станет копией текущего stdout (нормального выходного потока), прежде чем перенаправление stdout будет перенаправлено. Таким образом, команда stderr печатает на tty (или интерпретатор), как если бы он поступал из stdout, в то время как stdout отключен. Это поведение, которое вы хотите.
От man bash
:
Обратите внимание, что порядок перенаправления значителен. Например, команда
ls > dirlist 2>&1
направляет как стандартный вывод, так и стандартную ошибку в файл dirlist, а команда
ls 2>&1 > dirlist
направляет только стандартный вывод в файл dirlist, поскольку стандартная ошибка дублируется как стандартный вывод до того, как стандартный выход был перенаправлен на dirlist.