Труба | Перенаправление <> Приоритет - программирование
Подтвердить что ты не робот

Труба | Перенаправление <> Приоритет

Я хочу прояснить, когда труба | или перенаправление < > имеет приоритет в команде?

Это моя мысль, но нужно подтвердить, как это работает.

Пример 1:

sort < names | head
The pipe runs first:  names|head   then it sorts what is returned from names|head

Пример 2:

ls | sort > out.txt
This one seems straight forward by testing, ls|sort then redirects to out.txt

Пример 3:

Fill in the blank?  Can you have both a < and a > with a | ???
4b9b3361

Ответ 1

В терминах синтаксической группировки > и < имеют более высокий приоритет; то есть эти две команды эквивалентны:

sort < names | head
( sort < names ) | head

как и эти два:

ls | sort > out.txt
ls | ( sort > out.txt )

Но в терминах последовательного упорядочения сначала выполняется |; поэтому, эта команда:

cat in.txt > out1.txt | cat > out2.txt

будет заполняться out1.txt, а не out2.txt, потому что > out1.txt выполняется после | и, следовательно, заменяет его (поэтому выход не выводится на cat > out2.txt).

Аналогично, эта команда:

cat < in1.txt | cat < in2.txt

будет печатать in2.txt, а не in1.txt, потому что < in2.txt выполняется после | и, следовательно, заменяет его (поэтому никакой ввод не поступает из cat < in1.txt).

Ответ 2

От man bash (как и другие кавычки):

SHELL GRAMMAR
   Simple Commands
       A simple command is a sequence of optional variable assignments followed by
       blank-separated words and redirections, and terminated  by  a  control
       operator. The first word specifies the command to be executed, and is
       passed as argument zero.  The remaining words are passed as arguments
       to the invoked command.

       The return value of a simple command is its exit status, or 128+n if
       the command is terminated by signal n.

   Pipelines
       A pipeline is a sequence of one or more commands separated by one of
       the control operators | or |&.  The format for a pipeline is:

              [time [-p]] [ ! ] command [ [|⎪|&] command2 ... ]

Другими словами, вы можете иметь любое количество переназначений для (простой) команды; вы также можете использовать это как часть конвейера. Или, по-другому, перенаправление связывается более жестко, чем труба.

Есть несколько способов получить работу над этим (хотя они редко либо необходимы, либо эстетичны):

1. Вы можете создать "составную команду" и перенаправить в нее:

 Compound Commands
   A compound command is one of the following:

   (list)  list is executed in a subshell environment (see
           COMMAND EXECUTION ENVIRONMENT below).  Variable
           assignments  and  builtin  commands  that  affect  the
           shell environment do not remain in effect after the
           command completes.  The return status is the exit status of list.

   { list; }
          list  is  simply  executed  in the current shell environment.  list
          must be terminated with a newline or semicolon.  This is known as a
          group command. The return status is the exit status of list.  Note
          that unlike the metacharacters ( and ), { and } are reserved words
          and must occur where a reserved word is permitted to be recognized.
          Since they do not cause a word break, they must be separated from
          list by whitespace or another shell metacharacter.

Итак:

$ echo foo > input
$ { cat | sed 's/^/I saw a line: /'; } < input
I saw a line: foo

2. Вы можете перенаправить на канал, используя "замену процесса":

Process Substitution
   Process  substitution  is  supported on systems that support named pipes
   (FIFOs) or the /dev/fd method of naming open files.  It takes the form of
   <(list) or >(list).  The process list is run with its input or output
   connected to a FIFO or some file in /dev/fd.  The name of this file is
   passed as  an  argument  to  the  current  command  as the result of the
   expansion.  If the >(list) form is used, writing to the file will provide
   input for list.  If the <(list) form is used, the file passed as an argument
   should be read to obtain the output of list.

Итак:

 [email protected]$ cat > >(sed 's/^/I saw a line: /') < <(echo foo; echo bar)
 I saw a line: foo
 [email protected]$ I saw a line: bar

(Почему приглашение появляется до завершения вывода, и что делать с ним остаются в виде упражнений).

Ответ 3

Это немного неортодоксальный, но совершенно законный, разместить < в любом месте, где угодно, поэтому я предпочитаю это, поскольку он лучше иллюстрирует поток данных слева направо:

<input.txt sort | head >output.txt

Единственный раз, когда вы не можете этого сделать, - это встроенные команды структуры управления (for, if, while).

# Unfortunately, NOT LEGAL
<input.txt  while read line; do ...; done

Обратите внимание, что все это эквивалентные команды, но чтобы избежать путаницы, вы должны использовать только первый или последний:

<input.txt grep -l foobar
grep <input.txt -l foobar
grep -l <input.txt foobar
grep -l foobar <input.txt

Поскольку имя файла всегда должно появляться сразу после оператора перенаправления, я предпочитаю оставить свободное место между < и именем файла.

Ответ 4

Исправления:

Пример 1:

sort < names | head

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

В общем, вы можете читать слева направо. Стандартная идиома работает следующим образом:

  • Использование перенаправления ввода "<" сообщает программе чтение из файла вместо stdin
  • Использование перенаправления вывода " > " сообщает программе вывод в файл вместо stdout
  • Использование pipe "program_a | program_b" принимает все, что обычно выводится программой program_a в stdout, и передает его прямо в program_b, как если бы оно было прочитано из stdin.

Ответ 5

Это в значительной степени то, что я понимаю после некоторого чтения (в том числе ruakh)

Прежде всего, если вы переадресовываете несколько раз, все перенаправления выполняются, но только последнее перенаправление вступит в силу (если ни одно из предыдущих переназначений не вызывает ошибку)

  • например. cat < in1.txt < in2.txt эквивалентен cat < in2.txt, если in1.txt не существует, и в этом случае эта команда не будет выполнена (поскольку сначала выполняется < in1.txt)

  • Аналогично, с cat in.txt > out1.txt > out2.txt, только out2.txt будет содержать содержимое out2.txt, но поскольку сначала выполнялось > out1.txt, out1.txt было бы создано, если оно не существует.

Какая труба соединяет stdout предыдущей команды с stdin следующей команды, и это соединение происходит перед любыми другими перенаправлениями (из Bash вручную).

Итак, вы можете думать о

cat in1.txt > out1.txt | cat > out2.txt

как

cat in1.txt > pipe > out1.txt; cat < pipe > out2.txt

И применяя правило множественного перенаправления, упомянутое выше, мы можем упростить это для

cat in1.txt > out1.txt; cat < pipe > out2.txt

Результат. Содержимое in1.txt копируется в out1.txt, так как ничего не было записано в pipe


Используя другой пример ruakh,
cat < in1.txt | cat > in2.txt

примерно эквивалентен

cat > pipe < in1.txt; cat < pipe < in2.txt

который эффективно

cat > pipe < in1.txt; cat < in2.txt

Результат. На этот раз что-то записывается в pipe, но поскольку второй cat читает от in2.txt вместо pipe, печатается только содержимое in2.txt из.