Question

My Script:

#!/bin/bash

generic()
{

    echo $1;
    $1 > temp.txt 2>&1
}

generic "echo asd > /dev/null 2>&1; echo temp"

Expected Result:

  1. "asd" should go to /dev/null
  2. "temp" should go into temp.txt file.

Actual result:

  1. "asd > /dev/null 2>&1; echo temp" goes into temp.txt file.

Why only first echo statement runs and its output is getting redirect to temp.txt. Also, why is the second command treated as string?

Was it helpful?

Solution

You need to read the spec

(This is the POSIX sh spec, because bash has no real spec. bash tries to be compatible to the POSIX sh, but adds a crapload of unnecessary complexity. You should use #!/bin/sh instead as a beginner and whenever you want to write a sane script)

In particular, you can't store anything other than a single command in a variable. If you execute from a variable as you do by saying $1, then this is interpreted as a single command:

Splitting occurrs on whitespace or whatever is inside the IFS variable. In you example, this result in the following token list:

  1. echo
  2. asd
  3. >
  4. /dev/null
  5. 2>&1;
  6. echo
  7. temp

This list is then executed as a process, equivalent to writing in C execlp("echo", "echo", "asd", ">", "/dev/null", "2>&1;", "echo", "temp", NULL);.

Note that if you had written "$1" instead, this would result in the shell trying to launch a program called echo asd > /dev/null 2>&1; echo temp with no arguments.

If you instead want to re-evaluate a string as a shell command line, you need to use eval: eval "$1". But be aware of the security implications! Eval is by many considered evil.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top