0

I have a function that is supposed to evaluate the command passed to it as a string and display the output if the command failed. However, I'm getting some problems:

 $(echo "pwd")

works well (I see the files and directories). But, when I want to retrieve the output of this command:

 var=$(echo "pwd")
 echo ${var}

I get the following output:

 pwd

Why does assigning a variable to the output cause such a significant change? I've looked it up and it seems to be the recommended way of retrieving the output (i.e. see here).

Also, I based on this question and tried a different approach:

cmd="ls"
$cmd
file1 file2 dir1
a=$cmd
echo ${a}
ls

The result is the same like for the previous approach. I have the same issue with the answers here and here.

What am I doing wrong? How do I get the output of a string evaluated as a command?

Edit: I tried using $():

> var="pwd"
> ${var}
/c/Users/myDir
> $(${var})
bash: /c/Users/myDir: Is a directory

Edit2: I need to change the current working directory, so, as far as I know, I can't use $(). How can I get the output without creating a subprocess?

user2738748
  • 1,106
  • 2
  • 19
  • 36
  • Well, `var` is `pwd`, thus `echo ${var}` will output `pwd`... Did you mean to run `$(echo ${var})`? – blackghost Sep 05 '17 at 14:17
  • Think of `$()` as a variable and it will be easier to understand. Say a variable `$a` contains pwd, then just typing `$a` will run the command where `var=$a` will assign the contents of `$a` (that is pwd, not the output of the command) to `var`. The same goes for `$()`. – 123 Sep 05 '17 at 14:19

2 Answers2

4
$(command line)

means to exeecute command line, and then substitute its output into the command line in place of that syntax. If you just have

$(echo "pwd")

as the whole command line, it executes echo "pwd", gets the output pwd, and replaces that will the output, so it's equivalent to:

pwd

When you do:

var=$(echo "pwd")  

The output of echo "pwd" is the string pwd, so it's the same as:

var="pwd"

Then when you do:

echo ${var}

it's the same as

echo "pwd"

If you want to execute the command, don't put echo before it, just do:

${var}

just like you didn't put echo before $(echo "pwd") in your original command.

If you want to get the output of this in another variable, you have to use $() again:

res=$(${var})
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Thanks for the clarification-it helps. When I run `${var}`, I get the output I need, however, when I try to assign the output: `res=${var}`, `echo ${res}`, I still get the *pwd* command. How do I retrieve the output? – user2738748 Sep 05 '17 at 14:46
  • 1
    If you want to substitute the output, you have to use `$()`: `res=$(${var})` – Barmar Sep 05 '17 at 14:46
  • Barman, thank you. However, it doesn't work for me. See my edit. – user2738748 Sep 05 '17 at 15:01
  • You left out `res=` – Barmar Sep 05 '17 at 15:02
  • Yes, on purpose, to check if the command itself works before trying to assign its output to a variable. Now I confirmed that it works if I retrieve the output. But why doesn't it work when I don't assign the output to the variable? What's the difference for the command? – user2738748 Sep 05 '17 at 15:08
  • If you just want to execute the command, type `${var}`. You only need to use `$()` if you want to substitute the output into another command, such as a variable assignment. – Barmar Sep 05 '17 at 15:11
  • 1
    If you type `$(${var}))` it executes the command, then substitutes the output into the next command, so it tries to execute the output. But the output is the directory name, which isn't something you can execute. – Barmar Sep 05 '17 at 15:13
  • Barmar, it doesn't work if I want to change the current working directory using `var`. I've read that it's because `$()` creates a subshell. Is there a workaround for this? – user2738748 Sep 06 '17 at 07:29
  • Changing directory doesn't produce any output, so why would you need to put `$()` around that? – Barmar Sep 06 '17 at 17:38
  • But other commands do. I want to have a function `run_command` that will run any command and display the output if the command failed. I don't want to check the result of each bash command I execute. – user2738748 Sep 07 '17 at 13:24
  • 1
    Sorry, there's no general purpose way to do that for all commands. You can do it with external commands, because they always run in a new process anyway. But you can't do it with commands whose purpose is to change the current process's state, like `cd`. – Barmar Sep 07 '17 at 15:19
-1
$ cmd="ls"

To run $cmd and print its output to the terminal, just evaluate the variable:

$ "$cmd"
file1 file2 dir1

To capture $cmd's output, use $(...).

$ a=$("$cmd")
$ echo "$a"
file1
file2
dir1

Why does these work? Every time you write "$cmd", mentally substitute ls. Then you get

$ ls
file1 file2 dir1

and

$ a=$(ls)
$ echo "$a"
file1
file2
dir1

Why do the commands you tried fail? Because a=$cmd is equivalent to a=ls, which is the same as a="ls". It simply assigns the string ls to the variable a. It doesn't execute the ls command.

To call ls you either need to write ls with no variable assignment, or use $(...) to capture its output.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578