Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Условный конвейер Bash

Автор вопроса: Stefano d'AntonioОтветов: 3

Как я могу передать вывод команды на случай, если она вернет true?

function open
{
    TEMPFILE=$(mktemp -u)
    if ! gpg2 --quiet --decrypt --batch --passphrase "$2" "$1" 2> $TEMPFILE; then
        error $"Password errata od errore di lettura dal file\n\nDettagli:\n$(grep -v '^$' $TEMPFILE)"
        rm -f $TEMPFILE
        return 1
    fi
    rm -f $TEMPFILE
}

if ! open "$@" "$PASSWORD"; then
    exit 1
fi | <SOMECOMMAND>

Таким образом, он просто передает и не проверяет, возвращает ли open true или false, поэтому никогда не выполняет "exit 1".

Как я могу решить это без использования файлов (из соображений безопасности).

  • Полные источники: fpasswd-0.2-alpha на SourceForge Stefano d'Antonio 03.05.2012

bashfunctionif-statementpipeconditional

Ответы

Ответ 1 · рейтинг 9 · Gordon Davisson

Прежде чем я предложу решение, позвольте мне объяснить, что это сложнее, чем вы думаете. Основная проблема заключается во времени: функция open ... выдает выходные данные во время работы; он создает статус выхода после завершения работы (и, следовательно, после того, как он произвел свой вывод). Поскольку вы хотите делать с выводом разные вещи в зависимости от состояния выхода, вы должны временно хранить вывод где-то до тех пор, пока функция не завершится, и вы не сможете решить, что делать с выводом.

Канал по своей сути не будет работать для этого, потому что каналы не хранят данные (за исключением небольшого буферного пространства) - они передают данные "вживую" из одной программы в другую, и в этом случае вторая программа не может запуститься. пока не закончился первый. Обычно для этого идеально подходит временный файл (файлы предназначены для хранения данных), но вам это не нужно из соображений безопасности. Это в значительной степени оставляет данные где-то в ОЗУ (хотя это тоже не совсем безопасно...).

Ответ @Karoly Horvath предложил сохранить вывод в переменной bash (которая хранится в ОЗУ), но это не сработало, потому что bash не справляется с нулевыми байтами в значениях переменных. Итак, я предлагаю вариант, в котором вы используете "безопасную" кодировку данных и помещаете ее в переменную bash. Я использовал формат uuencode, но вы также можете использовать base64, шестнадцатеричный дамп и т. д.

if result=$(open "$@" "$PASSWORD" | uuencode -; exit ${PIPESTATUS[0]}); then
    echo "$result" | uudecode -p | SOMECOMMAND
fi

Обратите внимание, что PIPESTATUS - это башизм, поэтому вы должны начать сценарий с #!/bin/bash. Кроме того, если вывод слишком длинный, вы можете столкнуться с ограничениями на объем данных, которые bash хочет хранить/расширять/и т. д.; если это оказывается проблемой, все становится сложнее.

Кстати, если вы беспокоитесь о безопасности, не используйте параметр --passphrase gpg2 - передача парольной фразы в командной строке делает ее доступной, например. любой, кто запускает ps в нужное время, что является очень плохой идеей. В gpg2 есть много вариантов ввода парольной фразы, поэтому, пожалуйста, используйте лучший вариант.

Ответ 2 · Drake Clarris

Используйте именованный канал и сохраните возвращаемое значение

mkfifo piper;
open "$@" "$PASSWORD"; retval=$? > piper &
if [ x"$retval" != x0 ]
then
   rm piper
   exit 1
fi
<SOMECOMMAND> < piper
rm piper

Ответ 3 · Karoly Horvath

Следующий код должен условно передавать результат, если файл открывается успешно:

   result=open "$@" "$PASSWORD"
    if [ $? -gt 0 ]; then
      exit 1
    fi
    echo "$result" | <SOMECOMMAND>

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы