Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Today I'm learning something about fifo with this article: Introduction to Named Pipes, which mentions cat <(ls -l).

I did some experiments by using sort < (ls -l), which pops out an error:

-bash: syntax error near unexpected token `('`

Then I found I misadded an extra space in the command.

But, why this extra command will lead to this failure? Why must the redirect symbol be close to the (?

share|improve this question

3 Answers 3

up vote 29 down vote accepted

Because that's not an <, it's a <() which is completely different. This is called process substitution, it is a feature of certain shells that allows you to use the output of one process as input for another.

The > and < operators redirect output to and input from files. The <() operator deals with commands (processes), not files. When you run

sort < (ls)

You are attempting to run the command ls in a subshell (that's what the parentheses mean), then to pass that subshell as an input file to sort. This, however, is not accepted syntax and you get the error you saw.

share|improve this answer
    
Your answer is good, but then sort is attempting to read the subshell as its input file → this is obviously wrong, as Bash will not even parse the syntax. Neither ls nor sort is actually run. –  sebleblanc 17 hours ago
1  
@sebleblanc fair point, rephrased the answer, thanks. –  terdon 17 hours ago
    
There's no sub-shell in this case. < (ls) is not a valid token here. –  cuonglm 2 hours ago

Because that's how it's meant to be.

<(...) in bash is the syntax for process substitution. It's copied from the same operator in ksh.

<, (, ), |, &, ; are special lexical tokens in bash that are used to form special operators in different combinations. <, <(, <<, <&... each have their role. < is for redirection. <file, < file would redirect input from a file. <'(file)' would redirect input from a file called (file), but <(file) is a different operator that is not a redirection operator.

< (file) would be < followed by (file). In that context, in bash, (file) is not valid. (...) can be valid as a single token in some contexts like:

(sub shell)
func () {
  ...
}
var=(foo bar)

But not in

sort < (cmd)

In the fish shell, it's different. In fish, (...) is for command substitution (the equivalent of $(...) in bash). And < is for input redirection like in Bourne-like shells.

So in fish:

sort <(echo file)

would be the same as:

sort < (echo file)

That is:

sort < file

But that's something completely different from bash's process substitution.

In the yash shell, another POSIX shell, <(...) is not for process substitution but for process redirection

In there,

sort <(ls -l)

Short for:

sort 0<(ls -l)

is a redirection operator. It's more or less equivalent to:

ls -l | sort

While in bash, the <(ls -l) is expanded to the path of a pipe, so it's more like:

ls -l | sort /dev/fd/0

In zsh, (...) is overloaded as a globbing operator ((*.txt|*.png) would expand to txt and png files) and as glob qualifier (*(/) for instance expands to directory files).

In zsh, in:

sort < (ls -l)

That (ls -l) would be treated as a glob qualifier. The l glob qualifier is to match on number of links and expects a number after l (as in ls -ld ./*(l2) would list the files with 2 links), so that's why you get a zsh: number expected error there.

sort < (w) would have given a zsh: no matches found: (w) error instead as (w) matches the files with empty name that are writeable.

sort < (w|cat) would have sorted the content of the w and/or cat files in the current directory...

share|improve this answer

short answer

you can't use cmd1 < cmd2. (where cmdX are commands)

long answer

  • sort <(ls -l) will create a temporary file with the result of ls -l and "give" it to sort. it is equivalent to :

    ls -l > u
    sort u
    
  • sort < (ls -l) will

    1. fork a new shell, with ls -l
    2. try to use redirect operator < to give output to sort.

unfortunatly, you must use pipe ( | ) and its variant to redirect output of a shell/command to another.

correct syntax would have been

ls -l | sort
share|improve this answer
    
Temporary file - yes. Result - no. It will actually create a named pipe. –  aragaer 22 hours ago
    
@aragaer: It uses a pipe as you said but the processes will also run in parallel. It is more similar to: mkfifo -m 600 /tmp/fifo$$ ; ls >/tmp/fifo$$ & sort /tmp/fifo$$ ; rm /tmp/fifo$$ with the difference that the fifo is accessible only though the proc filesystem (on Linux) and it disappears immediately after closing its file descriptors. –  pabouk 21 hours ago
    
I was trying to keep explication simple. In any case for details see Stéphane Chazelas and Terdon's answers. –  Archemar 21 hours ago
    
@Archemar: I get that it's didactically useful to keep things simple, but the user who posed the question is trying to learn about FIFOs. In this case, it makes sense to answer the question in terms of FIFOs/named pipes. –  Rhymoid 17 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.