Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pipe | Redirection < > Precedence

Tags:

I want to make clear when does pipe | or redirection < > takes precedence in a command?

This is my thought but need confirmation this is how it works.

Example 1:

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

Example 2:

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

Example 3:

Fill in the blank?  Can you have both a < and a > with a | ??? 
like image 537
Kairan Avatar asked Oct 17 '12 19:10

Kairan


People also ask

What does || mean in shell script?

Just like && , || is a bash control operator: && means execute the statement which follows only if the preceding statement executed successfully (returned exit code zero). || means execute the statement which follows only if the preceding statement failed (returned a non-zero exit code).

What does Piping & Bash mean?

A pipe in Bash takes the standard output of one process and passes it as standard input into another process. Bash scripts support positional arguments that can be passed in at the command line.

What is pipe CMD?

Pipe shell command The | command is called a pipe. It is used to pipe, or transfer, the standard output from the command on its left into the standard input of the command on its right.

What is piping and redirection?

Redirection is (mostly) for files (you redirect streams to/from files). Piping is for processes: you pipe (redirect) streams from one process to another. Essentially what you really do is "connect" one standard stream (usually stdout ) of one process to standard stream of another process (usually stdin ) via pipe.


2 Answers

In terms of syntactic grouping, > and < have higher precedence; that is, these two commands are equivalent:

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

as are these two:

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

But in terms of sequential ordering, | is performed first; so, this command:

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

will populate out1.txt, not out2.txt, because the > out1.txt is performed after the |, and therefore supersedes it (so no output is piped out to cat > out2.txt).

Similarly, this command:

cat < in1.txt | cat < in2.txt 

will print in2.txt, not in1.txt, because the < in2.txt is performed after the |, and therefore supersedes it (so no input is piped in from cat < in1.txt).

like image 198
ruakh Avatar answered Sep 22 '22 12:09

ruakh


From man bash (as are the other quotes):

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 ... ] 

In other words, you can have any number of redirections for a (simple) command; you can also use that as part of a pipeline. Or, put another way, redirection binds more tightly than pipe.

There are a couple of ways to get work around this (although they're rarely either necessary or aesthetic):

1. You can make a "compound command" and redirect into it:

 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's 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. 

So:

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

2. You can redirect to a pipe using "process substitution":

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. 

So:

 rici@...$ cat > >(sed 's/^/I saw a line: /') < <(echo foo; echo bar)  I saw a line: foo  rici@...$ I saw a line: bar 

(Why the prompt appears before the output terminates, and what to do about it are left as exercises).

like image 26
rici Avatar answered Sep 20 '22 12:09

rici