11

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?

1

3 Answers 3

18

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"
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, any idea why "bash -c" prints the output in a single line? I would like to have the same output as entered manually at command line.
@stacker I don't think that's true. I get the same result as at the command line. Perhaps your grep is only returning a single line?
This happend because I forgot to enclose the variable in double quotes.
In my case I was trying to call a command that wasn't in the system path, I added its folder to my system path like shown here: unix.stackexchange.com/a/26059/61349
0

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

Comments

-3

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

1 Comment

The commands come from a different server and should be excecuted on the target machine. Thus it can't be hard coded.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.