Мне действительно понравилась идея использовать STDIN, поэтому, если кто-нибудь когда-нибудь попадет на эту страницу, подумайте, можете ли вы использовать STDIN в своей ситуации.
Но я хотел бы опубликовать свой собственный ответ, в котором используется модуль Expect Perl, потому что:
- Я использовал его, и было доказано, что он работает, по крайней мере, в Linux (хотя в вопросе в комментариях упоминается, что у модуля были проблемы с запуском в Windows);
- поскольку вопрос был назван без упоминания
cryptsetup
(который может принимать пароль на STDIN), поэтому модуль Expect здесь является общим решением, которое должно работать для других инструментов;
Мое решение ниже. Я не очень много читал документацию, поэтому могут быть лучшие способы сделать это. Для меня этого было достаточно, чтобы понять идею создания экземпляра объекта и методы ожидания/отправки.
Вы создаете экземпляр, как если бы вы только что запустили программу в терминале:
my $exp = Expect->new('progName', ($arg1, $arg2, $etc));
Затем с ним можно взаимодействовать с помощью методов expect
(который ожидает/подтверждает вывод программы пользователю) и send
(который позволяет пользователю "печатать").
expect
может вызываться как в скалярном, так и в списочном контексте (я использовал списочный), и он принимает строку или регулярное выражение того, какой результат ожидать и как долго. Если за указанное время не произошло ожидаемого вывода, выдается ошибка:
#sec to wait for #use regexp (don't match exactly) #regexp to match against
my @out = $exp->expect(10, '-re', 'smth');
send
просто принимает ввод
$exp->send('some chars');
Вот и все, нужно просто создать скрипт, который будет работать так, как будто это человек-пользователь.
И на всякий случай, если это может быть кому-то удобно, я опубликую свое полное конкретное решение для cryptsetup (я протестировал его на фиктивном томе, который он смог смонтировать, и я запустил его на реальном томе с 6к комбинаций перепробовал без заметных проблем):
*Я забыл закрыть здесь файловый дескриптор, поэтому нужно добавить close($fd)
, где это уместно
use strict;
use warnings;
use feature 'say';
# I installed Expect with its deps locally in my situation, so I had to change @INC
BEGIN {
unshift(@INC, './perl-mods/lib/perl5/');
unshift(@INC, './perl-mods/lib/perl5/x86_64-linux-thread-multi/');
}
use Expect;
my $devName = '/dev/sdb3';
my $combinationsFileName = 'combs.txt';
open(my $fd, '<', $combinationsFileName);
my $lineCount = 0;
while (<$fd>) {
my $pass = $_;
chomp($_);
say $_ . ' ' . ++$lineCount;
my $exp = Expect->new('cryptsetup', ('open', $devName, 'crypt-vol')) or die 'err 1';
my @out = $exp->expect(10, '-re', 'Enter passphrase') or die 'err 2';
$exp->send($pass);
@out = $exp->expect(10, '-re', 'No key available') or die 'err 3';
#if cryptsetup returned an error code
if ($out[1]) {
die $out[1] . ' ' . $pass;
}
}
person
Dmitry Koroliov
schedule
27.09.2020
expect
, предназначенный для работы с интерактивными программами, читающими из/dev/tty
. - person Jens   schedule 26.09.2020crypsetup
завершает работу с кодом 512 на втором или третьем элементе для ввода пароля - person Dmitry Koroliov   schedule 26.09.2020--key-file
тоже может быть STDIN. - person Sobrique   schedule 26.09.2020