Подтвердить что ты не робот

Что такое простое объяснение того, как трубы работают в Bash?

Я часто использую трубы в Bash, например:

dmesg | less

Хотя я знаю, что это выводит, он принимает dmesg и позволяет мне прокручивать его с less, я не понимаю, что | делается. Является ли это просто противоположность >?

  • Есть ли простое или метафорическое объяснение того, что | делает?
  • Что происходит, когда несколько труб используются в одной строке?
  • Является ли поведение труб согласованным везде, где оно появляется в сценарии Bash?
4b9b3361

Ответ 1

Труба Unix соединяет дескриптор файла STDOUT (стандартный вывод) первого процесса с STDIN (стандартный ввод) второго. Затем происходит то, что, когда первый процесс записывает в STDOUT, этот вывод может быть немедленно прочитан (из STDIN) вторым процессом.

Использование нескольких труб ничем не отличается от использования одного канала. Каждая труба независима и просто связывает STDOUT и STDIN соседних процессов.

Ваш третий вопрос немного неоднозначен. Да, трубы, как таковые, согласованы повсюду в bash script. Однако символ трубы | может представлять разные вещи. Двойной канал (||), например, представляет собой оператор "или".

Ответ 2

Каждый стандартный процесс в Unix имеет как минимум три файловых дескриптора, которые являются похожими интерфейсами:

  • Стандартный вывод, который является тем местом, где процесс печатает свои данные (большую часть времени консоль, то есть экран или терминал).
  • Стандартный ввод, который является местом, откуда он получает свои данные (большую часть времени он может быть чем-то вроде вашей клавиатуры).
  • Стандартная ошибка, которая является местом, где идут ошибки, а иногда и другие внеполосные данные. Это не интересно сейчас, потому что трубы обычно не справляются с этим.

Труба соединяет стандартный вывод процесса влево со стандартным входом процесса справа. Вы можете подумать об этом как о специальной программе, которая занимается копированием всего, что печатает одна программа, и подачи ее на следующую программу (после символа трубы). Это не совсем так, но это достаточно адекватная аналогия.

Каждая труба работает только на двух вещах: стандартный выход идет от его левого и ожидаемого справа от входного потока. Каждый из них может быть присоединен к одному процессу или другому биту конвейера, что имеет место в многотрубной командной строке. Но это не относится к фактической работе трубы; каждая труба делает свои собственные.

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

Ответ 3

В Linux (и Unix вообще) каждый процесс имеет три дескриптора файла по умолчанию:

  1. fd # 0 Представляет стандартный ввод процесса
  2. fd # 1 Представляет стандартный вывод процесса
  3. fd # 2 Представляет стандартный вывод ошибки процесса

Обычно, когда вы запускаете простую программу, эти файловые дескрипторы по умолчанию настраиваются следующим образом:

  1. вход по умолчанию считывается с клавиатуры
  2. Стандартный выход сконфигурирован как монитор
  3. Стандартная ошибка сконфигурирована как монитор

Bash позволяет нескольким операторам изменить это поведение (посмотрите, например, на>, >> и <operator). Таким образом, вы можете перенаправить вывод на нечто, отличное от стандартного вывода, или прочитать свой ввод от другого потока, отличного от клавиатуры. Особенно интересен случай, когда две программы взаимодействуют таким образом, что в качестве входных данных используется выход другого. Для облегчения этого сотрудничества Bash предоставляет операторам труб | , Обратите внимание на использование совместной работы вместо цепочки. Я избегал использования этого термина, поскольку на самом деле труба не является последовательной. Нормальная командная строка с трубами имеет следующий аспект:

    > program_1 | program_2 | ... | program_n

Вышеупомянутая командная строка немного вводит в заблуждение: пользователь может подумать, что программа_2 получает свой вход, как только программа_1 завершила свое выполнение, что неверно. Фактически, то, что bash делает, заключается в том, чтобы запускать ВСЕ программы параллельно, и он соответствующим образом настраивает входные выходы, поэтому каждая программа получает свой вход из предыдущего и выводит свой вывод на следующий (в установленном командной строке порядке).

Ниже приведен простой пример из Create pipe in C создания канала между родительским и дочерним процессом. Важной частью является вызов pipe() и как родитель закрывает fd 1 (сторона записи) и как дочерний элемент закрывает fd 1 (сторона записи). Обратите внимание, что труба является однонаправленным каналом связи. Таким образом, данные могут поступать только в одном направлении: fd 1 в направлении fd [0]. Для получения дополнительной информации взгляните на страницу руководства pipe().

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(void)
{
    int     fd[2], nbytes;
    pid_t   childpid;
    char    string[] = "Hello, world!\n";
    char    readbuffer[80];

    pipe(fd);

    if((childpid = fork()) == -1)
    {
            perror("fork");
            exit(1);
    }

    if(childpid == 0)
    {
            /* Child process closes up input side of pipe */
            close(fd[0]);

            /* Send "string" through the output side of pipe */
            write(fd[1], string, (strlen(string)+1));
            exit(0);
    }
    else
    {
            /* Parent process closes up output side of pipe */
            close(fd[1]);

            /* Read in a string from the pipe */
            nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
            printf("Received string: %s", readbuffer);
    }

    return(0);
}

И последнее, но не менее важное: при наличии командной строки в форме:

> program_1 | program_2 | program_3

Код возврата для всех строк устанавливается в последнюю команду. В этом случае program_3. Если вы хотите получить код промежуточного возврата, вы должны установить pipefail или получить его из PIPESTATUS.

Ответ 4

Труба выводит результат процесса, на выход я подразумеваю стандартный вывод (stdout в UNIX) и передает его на стандартный вход (stdin) другого процесса. Это не противоположность простого правого перенаправления >, целью которого является перенаправление вывода на другой вывод.

Например, возьмите команду echo в Linux, которая просто печатает строку, переданную в параметре на стандартном выходе. Если вы используете простое перенаправление, например:

echo "Hello world" > helloworld.txt

оболочка перенаправляет нормальный выход, изначально предназначенный для работы на stdout, и печатает его непосредственно в файле helloworld.txt.

Теперь, возьмите этот пример, который включает в себя канал:

ls -l | grep helloworld.txt

Стандартный вывод команды ls будет выводиться при вводе grep, так как это работает?

Такие программы, как grep, когда они используются без каких-либо аргументов, просто читают и ожидают, что что-то будет передано на их стандартный вход (stdin). Когда они что-то захватывают, например, вывод команды ls, grep действует нормально, обнаруживая, что вы ищете.

Ответ 5

Оператор трубы выводит результат первой команды, а "переводит" ее во вторую, подключая stdin и stdout. В вашем примере вместо вывода команды dmesg, идущей на stdout (и выкидывая ее на консоли), она переходит прямо в следующую команду.

Ответ 6

  • | помещает STDOUT команды слева на STDIN команды правой стороны.

  • Если вы используете несколько труб, это просто цепочка труб. Выход первых команд устанавливается на вход вторых команд. Выход второй команды устанавливается на следующий ввод команд. Так далее.

  • Он доступен во всех интерпретаторах на основе команд Linux/widows.

Ответ 7

Трубы очень просты.

У вас есть выход одной команды. Вы можете предоставить этот вывод в качестве входа в другую команду, используя канал. Вы можете запрограммировать столько команд, сколько хотите.

например: ls | grep my | grep файлы

Сначала перечисляются файлы в рабочем каталоге. Этот вывод проверяется командой grep для слова "my". Результат этого теперь входит во вторую команду grep, которая в конечном итоге ищет слово "файлы". Это оно.

Ответ 8

Если вы обрабатываете каждую команду unix как отдельный модуль,
но вам нужно, чтобы они разговаривали друг с другом, используя текст как согласованный интерфейс,
как это можно сделать?

cmd                       input                    output

echo "foobar"             string                   "foobar" 
cat "somefile.txt"        file                     *string inside the file*
grep "pattern" "a.txt"    pattern, input file      *matched string*

Вы можете сказать, что | - метафора для передачи эстафетной палочки в ретрансляционном марафоне.
Его форма даже одна!
cat -> echo -> less -> awk -> perl аналогичен cat | echo | less | awk | perl.

cat "somefile.txt" | echo
cat передать свой вывод для echo для использования.

Что происходит, когда имеется более одного входа?
cat "somefile.txt" | grep "pattern"
Существует неявное правило, в котором говорится: "Передавайте его как входной файл, а не шаблон" для grep.
Вы будете медленно развивать глаз для того, чтобы узнать, какой параметр по опыту.