Как я могу запустить cryptdisks _как обычный пользователь?

Ошибки в вашей команде связаны с тем, что fd 4 вообще не открыт.

На самом деле вы получаете два сообщения "плохой файловый дескриптор", одно из wc -l, а другое изcat <&4(илиxargs -a /dev/fd/4).

Вам понадобится безымянный канал, чтобы открыть fd 4, но единственный официальный способ получить безымянный канал в Bash — использовать команду coproc.

Тем не менее, для вашего конкретного варианта использования есть хороший короткий -вариант

Самый компактный способ :«подделки» безымянных каналов

Этот трюк не задокументирован, начиная с Bash v5, но работает по крайней мере на v4.3 (пока не удалось протестировать v5 ).

Он использует преимущества нескольких стандартных идиом, которые в совокупности позволяют получать произвольные «безымянные» каналы в системах, которые их поддерживают. Под «безымянный канал » я имею в виду «FIFO, не требующий предварительного создания файла типа pв файловой системе -с помощью mkfifoили эквивалентной команды ». (Это определение для безымянного -канала не является правильным, но я осмелюсь сказать, что это то, что действительно имеет смысл при использовании командной оболочки ).

Пример использования этих «безымянных» каналов сводится к следующему:

cat email.txt | ( : {pipe}<> <(:) ; tee >(sed -e '1,/^$/d' | wc -l >&${pipe}) | xargs -I% -a <({ read count ; echo $count; } <&${pipe}) sed -e '1,/^$/{/^Subject:/Is/$/ (%)/}' )

Приведенная выше командная строка должна дать ожидаемый результат в соответствии с вашим примером.

Разбито для объяснения:(только для ясности, не работает при копировании и вставке)

cat email.txt | \  # pipe data to...
    ( \  # a compound statement, which...
     : {pipe}<> <(:) ; \ #... first opens the unnamed pipe in RW mode and put its fd into the (arbitrary) variable ${pipe}
    tee \ # then mirrors the data from main stdin to...
        >( \ # the side processing of main input...
            sed -e '1,/^$/d' | wc -l \ #... which counts the body lines sending the result...
            >&${pipe} \ #... to the unnamed pipe
         ) \
    | \ # the tee also pipes all main input to...
    xargs -I% -a \ # an xargs that reads iterative lines from...
        <({ read count ; echo $count ; } <&${pipe}) \ # a compound command that reads the one-single line (being the count provided by wc) from ${pipe} fd, and echoes it back to xargs -a
        sed -e \ # that finally executes the sed command which looks for Subject: line in header part
        '/1,^$/{/^Subject:/Is/$/ (%)/}' ; \ # to append it with the count number
    )

Несколько дополнительных замечаний:

  • требуется открытие безымянного канала RW, так как я не нашел способа открыть обычную пару каналов, один из которых предназначен для чтения -, а другой — для записи -конец
  • это означает, что не может быть обычного события EOF, уведомляющего часть чтения о том, что данные больше не поступают, вы должны сделать это самостоятельно каким-то другим способом, но здесь мы можем воспользоваться тем фактом, что только одна строка когда-либо представляет интерес, поэтому достаточно одного единственного read.Если вместо этого вам нужно будет прочитать несколько строк из бокового -канала, вам понадобится какое-то уведомление EOF в полосе -, например, простая строка EOF для добавления в самый конец вывода, а затем отфильтровать во время чтения для xargs -aи залог -из чтения. Это вполне выполнимо, но довольно долго печатать в командной строке. Избавление от строки EOF в диапазоне -также возможно, но еще более сложно
  • управление этими безымянными каналами полностью зависит от вас, поэтому вам может потребоваться явно закрыть их с помощью exec {pipe}<&-; в этом примере мне не нужно было этого делать, потому что fd создается в подпроцессе

Для полноты картины ниже приведена эквивалентная версия с использованием coproc, которая обеспечивает настоящий безымянный канал через обычную пару взаимосвязанных файловых дескрипторов -.

Официальный способ для безымянных пайпов :coproc

Может быть довольно много подходов к использованию coproc, однако для вашего случая я полагаю, что лучшим будет следующий:

cat email.txt | (coproc cat ; : {input}<&${COPROC[0]} {output}>&${COPROC[1]} ; tee >(sed -e '1,/^$/d' | wc -l >&${output}) | xargs -I% -a <(exec cat <&${input}) sed -e '1,/^$/{/FOO/Is/$/ (%)/}' & )

Разбито для объяснения:(только для ясности, не работает при копировании и вставке)

cat email.txt | \ # pipe data to...
    ( \ # a subcommand statement, which...
    coproc cat ; \  #... first spawns the coprocess, a simple cat command acting as a simple line-oriented bridge
    : {cp_output}<&${COPROC[0]} {cp_input}>&${COPROC[1]} ; \ # then copies coproc’s own fds into new ones whose number are put into (arbitrary) variables ${cp_output} and ${cp_input} 
    tee \ # and then mirrors the data from main stdin to...
        >( \ # the side processing of main input...
            sed -e '1,/^$/d' | wc -l \ #... which counts the body lines sending the result...
            >&${output} \ #... to the (bridging) coproc
          ) \
    | \ # the tee also pipes all main input to...
    xargs -I% -a \ # an xargs that reads iterative lines from...
        <(exec cat <&${pipe}) \ # another cat that reads from the coproc bridging the count provided by wc, and echoes it back to xargs -a
        sed -e \ # that finally executes the sed command which looks for Subject: line in header part
        '/1,^$/{/^Subject:/Is/$/ (%)/}' ; \ # to append it with the count number
    )

Еще несколько дополнительных примечаний:

  • рекомендуется оператор подкоманды, чтобы никакие данные coproc (, т.е. процесс и fds )не просачивались в интерактивный bash (при условии, что вы запускаете этот зверь в интерактивном режиме!)
  • в противном случае управление данными этого coproc полностью зависит от вас, поэтому вам может потребоваться, например, явно закрыть fds с помощью exec {cp_input}<&-илиexec {COPROC[1]}<&-
  • вы можете использовать любую команду с coproc, но я всегда находил, что использование простого catсоединения двух fds является удобным решением общего назначения; однако вы можете оптимизировать производительность, если вам удастся внедрить любой рабочий процесс в сам coproc; в этом примере вам потребуется много переупорядочивать всю командную строку
  • согласно документации Bash v4,Bash одновременно поддерживает только один coproc
  • однако, по крайней мере, начиная с версии 4.3, он принимает больше копроцессов, хотя и с явным предупреждением, а в документации по Bash версии 5 не указывается никаких ограничений
  • в случае большего количества копроцессов вы должны использовать явные имена для каждого копроцесса (подробности см. в документации)
  • перемещение/копирование fd coproc в произвольные fds требуется для того, чтобы они выдержали конвейеры и подстановки процессов, используемые в этом примере, потому что массив ${COPROC[*]}не экспортируется в дочерние процессы, а его собственные fds всегда закрываются при выполнении
  • здесь мы можем воспользоваться преимуществом xargs -a, который активно читает из стандартного ввода и файл, указанный в -a, таким образом не позволяя teeзаполнять буферы каналов, в противном случае тупик, и вам понадобится более сложный подход, чтобы избежать его
0
08.07.2020, 23:53
1 ответ

Насколько мне известно, в SystemD ничего подобного нет.

Вы можете использовать

  • sudo
  • udisksctl unlockс конфигурацией PolKit для определенных пользователей или групп
1
18.03.2021, 23:21

Теги

Похожие вопросы