Let's suppose the output of a chain of pipes command1 | command2 | comamnd3
is the name of a file and you want to redirect <
this file to another command.
I'd like to use something like command4 < command1 | command2 | comamnd3
but it seems that <
operator has preference over |
For example, I can search for the "hello" word in the most recent file doing:
grep "hello" $(ls -t | head -n1)
But, how to do that without the using of subshells, just using pipes and redirections? I.e grep "hello" < ls -t | head -n1
(*)
(*) Yes, I know I don't need redirection for grep
. This is just an example
CodePudding user response:
You should rely on sub shells by:
( command4 < command1 ) | command2 | comamnd3
CodePudding user response:
command4 < command1 | command2 | comamnd3
Why don't move your command to the end of pipechain, as it should be logical? :
command1 | command2 | command3 | command4
| is not just a redirection, it is pipe with redirection between two separate processes, when < and > are redirection of stdout/stdin belong to the same process, that is why they executes before '|' pipe.
If you want to put your command4 in the beginning by any personal reasons, you can use ( ) to join other commands, like that:
command4 < ( command1 | command2 | command3 )
And your example:
grep "hello" < ls -t | head -n1 (*)
For such things you can use xargs:
ls -t | head -n1 | xargs grep "hello"
CodePudding user response:
You seem missunderstanding what subshell mean. As shell is a shell, every other biraries you run will implie a subprocess:
In
grep "Foo bar" $(/bin/ls -1t|head -n1)
You run two subcommands: ls | head
, then retrieve answer to pass them as argument to a third subcommand: grep
, you will run 3 subprocess.
You could avoid use of head
by using read
builtin:
read -r filename < <(/bin/ls -1t)
grep "Foo bar" "$filename"
As read
read by line, only one line (the first) will be stored into filename variable. In this, only ls
and grep
will generate subprocess.
Note différence between $(...)
and <(...)
, where first syntax will pass answer as content of string, but second argument will generate an unnamed fifo then pass the answer as input stream. Then note the redirection <
and a space before <(...)
telling read
to take his input from the unnamed fifo.
Reversing order of a pipe chain could be usefull if you try to store his result into a variable:
head -n 1 < <(tac < <(grep 456 < <(seq {120,124}000)))
123456
seq {120,124}000 | grep 456 | tac | head -n1
123456
{ tac | head -n1 ;} < <(seq {120,124}000 | grep 456)
123456
And so on...