12
#!/bin/bash

# 1st part
ret=$(ps aux | grep -v grep)    # thats OK 
echo $ret

# 2nd part
cmd="ps aux | grep -v grep"     # a problem with the pipe | 
ret=$($cmd)         
echo $ret

How can I use a command-string as I have in the 2nd part? Think the pipe is the problem. Tried to escape it but it did not help. Get some snytax error of ps.

Thanks!

chris01
  • 10,921
  • 9
  • 54
  • 93

2 Answers2

12

You need eval:

ret=$(eval "$cmd")
Jack
  • 5,801
  • 1
  • 15
  • 20
  • 4
    Note that it's rather hard to get quoting and backslashing right in nested evals; and it's extremely insecure to use eval if parts of the string come from the user. – choroba Jan 04 '18 at 15:23
  • Thank you for an actually working answer! now, if you could explain why you can't just do ret=eval $cmd – Al Ro Mar 30 '22 at 19:31
  • @AlRo, first: `ret=eval $cmd` runs `$cmd` with `ret` temporarily set to the string `eval`, and because the `eval` is data there instead of a command, the invocation of `$cmd` is subject to the bugs in [BashFAQ #50](https://mywiki.wooledge.org/BashFAQ/050). Second: if you don't quote the `"$cmd"`, then its contents get word-split and glob-expanded _before_ being glued back into a single string and passed to `eval`. The details of exactly how that corrupts your command depends on the details of the command and the files in your current working directory, but it's basically never something good. – Charles Duffy Aug 31 '23 at 15:30
7

Using eval is not recommended here. It can lead to unexpected results, especially when variables can be read from untrusted sources (See BashFAQ/048 - Eval command and security issues.

You can solve this in a simple way by defining and calling a function as below

ps_cmd() {
    ps aux | grep -v grep
}

and use it in the script as

output="$(ps_cmd)"
echo "$output"

Also a good read would be to see why storing commands in a variable is not a good idea and has a lot of potential pitfalls - BashFAQ/050 - I'm trying to put a command in a variable, but the complex cases always fail!

Inian
  • 80,270
  • 14
  • 142
  • 161