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

Как я могу передать вывод команды на случай, если она вернет 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».

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


person Stefano d'Antonio    schedule 02.05.2012    source источник
comment
Полные источники: fpasswd-0.2-alpha на SourceForge   -  person Stefano d'Antonio    schedule 03.05.2012


Ответы (3)


Прежде чем я предложу решение, позвольте мне объяснить, что это сложнее, чем вы думаете. Основная проблема заключается во времени: функция 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 есть много вариантов ввода парольной фразы, поэтому, пожалуйста, используйте лучший вариант.

person Gordon Davisson    schedule 02.05.2012
comment
Спасибо, позже я попробую использовать uuencode и дам вам знать. Спасибо также за объяснение; теперь я буду использовать echo $PASS | gpg2 -d --batch --passphrase-fd 0 $ФАЙЛ, это безопасно, верно? - person Stefano d'Antonio; 03.05.2012
comment
Однако, пока я искал альтернативу, я использовал функцию открытия два раза, один раз для проверки (›/dev/null) и еще один для использования данных... Но это пустая трата ресурсов и времени. (Тем не менее, парольная фраза находится в ps всего на несколько секунд, но вы абсолютно правы в том, что я не должен использовать --passphrase) - person Stefano d'Antonio; 03.05.2012
comment
Да, использование echo "$PASSWORD" | gpg2 ... --passphrase-fd 0 (обратите внимание на двойные кавычки вокруг $PASSWORD) должно быть безопасным, потому что echo запускается не как обычная команда, а как встроенная в подоболочку, поэтому ее аргумент не виден ps и тому подобным. - person Gordon Davisson; 03.05.2012
comment
В данной ситуации это выглядит как лучший способ сделать это. - person Gordon Davisson; 03.05.2012
comment
Я хочу, чтобы у моего программного обеспечения было меньше возможных зависимостей, поэтому я использовал base64... Он отлично работает! Большое спасибо! Также для $PIPESTATUS я не знал! - person Stefano d'Antonio; 03.05.2012
comment
На самом деле, я ожидаю, что uuencode будет более широко доступен, чем какой-либо конкретный инструмент base64 (хотя последние версии утилиты uuencode поддерживают кодировку base64 с флагом -m). - person Gordon Davisson; 03.05.2012
comment
В моем Gentoo base64 находится в coreutils, uuencode в sharutils, что менее необходимо для системы (на самом деле, у меня его нет). - person Stefano d'Antonio; 04.05.2012
comment
Странный; uuencode входит в единую спецификацию Unix с по крайней мере версии 2 (1997 г.) , а base64 отсутствует даже в довольно последних версиях. О, ну, действуйте с тем, что работает в вашей ситуации... - person Gordon Davisson; 04.05.2012
comment

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

mkfifo piper;
open "$@" "$PASSWORD"; retval=$? > piper &
if [ x"$retval" != x0 ]
then
   rm piper
   exit 1
fi
<SOMECOMMAND> < piper
rm piper
person Drake Clarris    schedule 02.05.2012
comment
Не сработает. Во-первых, retval устанавливается в подоболочке (из-за &). Во-вторых, команда open ..., вероятно, заблокирует ожидание чтения данных из канала, но ничего не может быть прочитано из канала до тех пор, пока не завершится open .... - person Gordon Davisson; 02.05.2012
comment
Я только что протестировал это (хотя, очевидно, не использовал open), и он работал, как и ожидалось... как при сбое команды, отправляемой в канал, так и при успешном вводе оператора then, когда он должен. И команда open пишет в трубу, а не читает - person Drake Clarris; 02.05.2012
comment
Не работает для меня. Я попробовал false; retval=$? >/dev/null &, дождался окончания, затем echo $retval и получил пустую строку. Что касается блокировки открытой команды, если вы попытаетесь записать слишком много в канал (обычно 64 КБ, см. здесь), процесс записи заблокируется в ожидании того, что что-то прочитает данные и освободит место в конвейере. - person Gordon Davisson; 02.05.2012
comment
Только что понял, что упростил свой тест до такой степени, что удалил &.. упс, моя ошибка - person Drake Clarris; 02.05.2012
comment
Как я уже сказал, я не хочу использовать ни файл, ни именованные каналы, содержимое полно паролей в открытом виде. - person Stefano d'Antonio; 03.05.2012

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

   result=open "$@" "$PASSWORD"
    if [ $? -gt 0 ]; then
      exit 1
    fi
    echo "$result" | <SOMECOMMAND>
person Karoly Horvath    schedule 02.05.2012
comment
вывод open содержит новую строку и другой непечатаемый символ, это не работает так. - person Stefano d'Antonio; 02.05.2012
comment
новая строка не проблема... какая у вас SOMECOMMAND? - person Karoly Horvath; 02.05.2012
comment
Вы правы насчет новой строки, но она содержит и другие непечатаемые символы (например, \0), которые не сохраняются. НЕКОТОРАЯ КОМАНДА - это функция, которая печатает пароли (через zenity, если графический, stdout, если нет). Я не могу использовать файл из соображений безопасности. - person Stefano d'Antonio; 02.05.2012
comment
@Uno Вы всегда должны цитировать вывод подпроцесса. попробуй result="$(open $@ $PASSWORD)" (ненавижу клещей) - person KurzedMetal; 02.05.2012
comment
@KurzedMetal: open нужно будет напечатать код возврата, т. е. printf "1\n"f, чтобы значение было захвачено с помощью замены cmd (т. е. result=$(...)). return устанавливает только значение $? вызывающего абонента. Вполне вероятно, что пока присваивание result=...whatever не вызовет синтаксической ошибки, значение $? теперь будет отражать успешное присваивание result, а «возвращенное» значение будет потеряно. Нет времени протестировать. Всем удачи. - person shellter; 02.05.2012
comment
нет, присвоение внутреннее, не меняется $?. также обратные кавычки работают нормально, цитирование не поможет. - person Karoly Horvath; 02.05.2012
comment
@shellter $? вернуть код выхода open, даже если он находится в подоболочке. - person Stefano d'Antonio; 03.05.2012
comment
@Uno: мне удалить свой комментарий? Удачи. - person shellter; 03.05.2012
comment
@shellter Нет, это точно не мешает! :) В любом случае, спасибо! - person Stefano d'Antonio; 03.05.2012