Reputation: 68942
I tried to run commands using pipes.
Basic:
single="ls -l"
$single
which works as expected
Pipes:
multi="ls -l | grep e"
$multi
ls: |: No such file or directory
ls: grep: No such file or directory
ls: e: No such file or directory
...no surprise
bash < $multi
$multi: ambiguous redirect
next try
bash $multi
/bin/ls: /bin/ls: cannot execute binary file
Only
echo $multi > tmp.sh
bash tmp.sh
worked.
Is there a way to execute more complex commands without creating a script for execution?
Upvotes: 11
Views: 20141
Reputation: 694
You need a heredoc
to do this correctly. In answer to POSIX compliant way to see if a function is defined in an sh script, I detailed how to read a script into a variable, programmatically parse it for information and/or modify it as necessary, then execute it from another script or shell function. That's basically what you're trying to do, and the heredoc
makes it possible because it provides a file descriptor:
% multi='ls -l | grep e'
% sh <<_EOF_
> ${multi}
> _EOF_
< desired output >
That would solve your simple example case. See my other answer for more.
-Mike
Upvotes: 0
Reputation: 342303
when you want to run commands with pipes, just run it. Don't ever put the command into a variable and try to run it. Simply execute it
ls -l |grep
If you want to capture the output, use $()
var=$(ls -l |grep .. )
Upvotes: -3
Reputation: 38462
You're demonstrating the difference between the shell and the kernel.
"ls -l" is executable by the system execve() call. You can man execve
for details, but that's probably too much detail for you.
"ls -l | grep e" needs shell interpretation to set up the pipe. Without using a shell, the '|' character is just passed into execve() as an argument to ls. This is why you see the "No such file or directory" errors.
Solution:
cmd="ls -l | grep e"
bash -c "$cmd"
Upvotes: 18