Bash script - variable content as a command to run

Bash

Bash Problem Overview


I have a Perl script that gives me a defined list of random numbers that correspond to the lines of a file. Next I want to extract those lines from the file using sed.

#!/bin/bash
count=$(cat last_queries.txt | wc -l)
var=$(perl test.pl test2 $count)

The variable var returns an output like: cat last_queries.txt | sed -n '12p;500p;700p'. The problem is that I can't run this last command. I tried with $var, but the output is not correct (if I run manually the command it works fine, so no problem there). What is the correct way to do this?

P.S: Sure I could do all the work in Perl, but I'm trying to learn this way, because it could help me in other situations.

Bash Solutions


Solution 1 - Bash

You just need to do:

#!/bin/bash
count=$(cat last_queries.txt | wc -l)
$(perl test.pl test2 $count)

However, if you want to call your Perl command later, and that's why you want to assign it to a variable, then:

#!/bin/bash
count=$(cat last_queries.txt | wc -l)
var="perl test.pl test2 $count" # You need double quotes to get your $count value substituted.

...stuff...

eval $var

As per Bash's help:

~$ help eval
eval: eval [arg ...]
    Execute arguments as a shell command.

    Combine ARGs into a single string, use the result as input to the shell,
    and execute the resulting commands.

    Exit Status:
    Returns exit status of command or success if command is null.

Solution 2 - Bash

You're are probably looking for eval $var.

Solution 3 - Bash

There're 2 basic ways of executing a string command in a shell script whether it's given as parameter or not here's.

COMMAND="ls -lah"
$(echo $COMMAND)

or

COMMAND="ls -lah"
bash -c $COMMAND

Solution 4 - Bash

line=$((${RANDOM} % $(wc -l < /etc/passwd)))
sed -n "${line}p" /etc/passwd

just with your file instead.

In this example I used the file /etc/password, using the special variable ${RANDOM} (about which I learned here), and the sed expression you had, only difference is that I am using double quotes instead of single to allow the variable expansion.

Solution 5 - Bash

In the case where you have multiple variables containing the arguments for a command you're running, and not just a single string, you should not use eval directly, as it will fail in the following case:

function echo_arguments() {
  echo "Argument 1: $1"
  echo "Argument 2: $2"
  echo "Argument 3: $3"
  echo "Argument 4: $4"
}

# Note we are passing 3 arguments to `echo_arguments`, not 4
eval echo_arguments arg1 arg2 "Some arg"

Result:

Argument 1: arg1
Argument 2: arg2
Argument 3: Some
Argument 4: arg

Note that even though "Some arg" was passed as a single argument, eval read it as two.

Instead, you can just use the string as the command itself:

# The regular bash eval works by jamming all its arguments into a string then
# evaluating the string. This function treats its arguments as individual
# arguments to be passed to the command being run.
function eval_command() {
  "$@";
}

Note the difference between the output of eval and the new eval_command function:

eval_command echo_arguments arg1 arg2 "Some arg"

Result:

Argument 1: arg1
Argument 2: arg2
Argument 3: Some arg
Argument 4:

Solution 6 - Bash

Better ways to do it

Using a function:

# define it
myls() {
    ls -l "/tmp/test/my dir"
}

# run it
myls

Using an array:

# define the array
mycmd=(ls -l "/tmp/test/my dir")

# run the command
"${mycmd[@]}"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBarataView Question on Stackoverflow
Solution 1 - BashhmontoliuView Answer on Stackoverflow
Solution 2 - BashAugust KarlstromView Answer on Stackoverflow
Solution 3 - Bashuser8766193View Answer on Stackoverflow
Solution 4 - BashnhedView Answer on Stackoverflow
Solution 5 - BashAjedi32View Answer on Stackoverflow
Solution 6 - Bash7beggars_nnnnmView Answer on Stackoverflow