Это довольно сложная команда. Я ответил на ваши вопросы прямо в самом конце, а пока все это распаковка самой команды. Я старался быть исчерпывающим, поэтому местами может быть немного больше деталей, чем вам нужно.
Скобки создают подоболочку:
( x y z )
означает создать новую оболочку из текущей, выполнить x y z
в (и затем вернуться к текущей оболочке ). Подоболочка наследует все, что касается текущего, но является отдельным процессом :, что означает, что в него могут быть переданы входные данные, и внутри него могут быть свои собственные изменения среды, которые не влияют на родителя.
Каждый открытый файл имеет числовой «дескриптор файла» , связанный с ним. «Файл» в этом контексте включает в себя любой вид входного или выходного потока, включая реальные файлы, сокеты и стандартные потоки ввода-вывода. Числа — это дескрипторы, которые можно использовать непосредственно с функцией C read
, чтобы определить, о каком потоке вы говорите, и с соответствующим системным вызовом, предоставляемым операционной системой, вместе со всеми другими операциями ввода-вывода. функции.
4<&0
выполняет перенаправление клонирование стандартного дескриптора входного файла (0 )в качестве дескриптора файла 4 .Это означает, что FD 0 копируется в 4 , а не наоборот. В данном случае это изменение открытых файлов для подоболочки, которая предшествует перенаправлению. На данный момент это просто создание другого «имени» для входного потока. Однако ключевой момент заключается в том, что после этого два имени становятся независимыми друг от друга. :FD 4 всегда будет ссылаться на один и тот же поток, даже если FD 0 будет изменен, чтобы ссылаться на что-то другое, и они расходятся.
/dev/fd/4
— это (не -стандартный )способ доступа программы к собственным дескрипторам открытых файлов . В Linux это символическая ссылка на /proc/self/fd
, которая реифицирует таблицу файловых дескрипторов текущего процесса. Программа может open("/dev/fd/4", O_RDONLY)
и получить дескриптор файла, который ссылается на поток, который эта программа имеет на FD 4 (, такой как 4
сам ). Что касается программы, то это обычный файл, который можно открывать, закрывать и читать, как и любой другой. Поскольку дескрипторы открытых файлов наследуются подпроцессами, main_command
имеет тот же файловый дескриптор 4, что и подоболочка, внутри которой он находится, поэтому /dev/fd/4
работает и там.
cmd2 | x
запускает cmd2
и подключает свой стандартный выход к стандартному входу -или FD 0 -из x
. В вашей команде x
— это выражение подоболочки.
Наша общая команда
cmd2 | ( main_command /dev/fd/4 ) 4<&0
затем состоит из трех основных частей:
cmd2
и направьте его вывод в ( main_command /dev/fd/4 ) 4<&0
. 4
другое имя для потока, идентифицированного стандартным вводом )из ( main_command /dev/fd/4 )
0
(. main_command
с /dev/fd/4
в качестве аргумента, который будет (предположительно )открываться как файл и считываться из него, получая результат cmd2
. Окончательный эффект заключается в том, что main_command
получает аргумент имени пути, который он может открыть и прочитать вывод cmd2
, точно так же, как это произошло бы при подстановке процесса Bash main_command <(cmd2)
:, что, вероятно, даст /dev/fd/63
как аргумент и в остальном действовать очень похоже внутри.
Для полной команды
( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
у нас есть вложенные подоболочки :это потому, что мы хотим сделать две копии стандартного ввода, но это два разных стандартных ввода:один является выходом cmd1
, который помещается в FD 3 после передается в более крупную подоболочку, а другой является выходом cmd2
, который помещается в FD 4 после передачи в самую внутреннюю подоболочку. Оба 0
относятся к стандартному вводу, но стандартный ввод каждой команды отличается, потому что в него передается что-то другое.
Думаю, это самая запутанная часть вопроса. Каждая команда -здесь, каждая подоболочка -имеет свой собственный стандартный ввод, передаваемый из cmd1
или cmd2
, и этот уникальный стандартный поток ввода получает псевдоним 3
или 4
. ]. Эти открытые файловые дескрипторы наследуются следующим уровнем подоболочки и дочерними командами, поэтому /dev/fd/3
в самой внутренней команде ссылается на то же самое, что и снаружи, хотя стандартный ввод теперь указывает на что-то другое.
Внешние круглые скобки не являются обязательными, хотя они делают его немного более надежным для некоторых команд и, вероятно, являются хорошей практикой. Внутренние :используются для создания нового подпроцесса, внутри которого может быть свой собственный набор перенаправлений и собственный стандартный поток ввода.
Самое внутреннее перенаправление на самом деле избыточно:cmd2 | main_command /dev/fd/3 /dev/stdin
также будет работать, так как в стандартный ввод больше не вносятся изменения.
Для прямого ответа на ваши вопросы:
How do I unpack the command at the beginning of the question?
Распаковка - это весь пост до этого момента.
What do the parentheses do?
Круглые скобки создают подоболочку, независимый процесс оболочки, который можно использовать как любую другую команду, в том числе с передачей в нее входных данных, но он может выполнять внутри обычные операции оболочки, такие как перенаправления.
Is my explanation of the simpler command correct?
Частично. 4<&0
говорит, что файловый дескриптор 4 будет указывать на стандартный ввод и, что важно, на то, что сейчас называется стандартным вводом -, а не на концепцию стандартного ввода. /dev/fd/4
— это «файл» в том смысле, что «всё есть файл», а точнее — это путь, который при открытии возвращает вам FD 4.
Вы уверены, что ваши серверы поддерживают http/2 без шифрования?
Попробуйте это:
backend servers
mode http
server S1 XXX.XXX.XXX:80 proto h2
server S2 XXX.XXX.XXX:80 proto h2
Если у вас включено шифрование, попробуйте это:
backend servers
mode http
server S1 XXX.XXX.XXX:443 ssl alpn h2
server S2 XXX.XXX.XXX:443 ssl alpn h2