0

Trying to run a command as a variable but I am getting strange results

Expected result "1" :

grep -i nosuid /etc/fstab | grep -iq nfs 
echo $?
1

Unexpected result as a variable command:

cmd="grep -i nosuid /etc/fstab | grep -iq nfs"
$cmd
echo $?
0

It seems it returns 0 as the command was correct not actual outcome. How to do this better ?

1

2 Answers 2

4

You can only execute exactly one command stored in a variable. The pipe is passed as an argument to the first grep.

Example

$ printArgs() { printf %s\\n "$@"; }
# Two commands. The 1st command has parameters "a" and "b".
# The 2nd command prints stdin from the first command.
$ printArgs a b | cat
a
b
$ cmd='printArgs a b | cat'
# Only one command with parameters "a", "b", "|", and "cat".
$ $cmd
a
b
|
cat

How to do this better?

Don't execute the command using variables. Use a function.

$ cmd() { grep -i nosuid /etc/fstab | grep -iq nfs; }
$ cmd
$ echo $?
1

Solution to the actual problem

I see three options to your actual problem:

  • Use a DEBUG trap and the BASH_COMMAND variable inside the trap.
  • Enable bash's history feature for your script and use the hist command.
  • Use a function which takes a command string and executes it using eval.

Regarding your comment on the last approach: You only need one function. Something like

execAndLog() {
    description="$1"
    shift
    if eval "$*"; then
        info="PASSED: $description: $*"
        passed+=("${FUNCNAME[1]}")
    else
       info="FAILED: $description: $*"
       failed+=("${FUNCNAME[1]}")
    done
}

You can use this function as follows

execAndLog 'Scanned system' 'grep -i nfs /etc/fstab | grep -iq noexec'

The first argument is the description for the log, the remaining arguments are the command to be executed.

Sign up to request clarification or add additional context in comments.

6 Comments

Don't execute the command using variables. Use a function. should be in bold letters :-)!
The reason I was doing it this way was because I wanted to print the command used in another variable... basically build a log of the command echo "Failed: ${cmd}" ..
@MikeQ If you give a bit more explanation on what you actually need we might be able to help you. Is printing failed commands (that don't have to be stored inside variables) all you want to do? Edit your question.
FYI : I added "bonus question" to my question to show what I'm doing ... basically I was thinking it would be nicer to just use a variable inside of the "info" variable ..
@MikeQ I responded by adding the three approaches at the end. Seems like they were not explained sufficiently enough though. You only need one function. I added the function and an example that should be equivalent to the code you removed from your answer (except that I used lowercase variable names because that's the recommended style).
|
1

using bash -x or set -x will allow you to see what bash executes:

> cmd="grep -i nosuid /etc/fstab | grep -iq nfs"
> set -x
> $cmd
+ grep -i nosuid /etc/fstab '|' grep -iq nfs

as you can see your pipe | is passed as an argument to the first grep command.

3 Comments

Gotcha .. that was the issue ... I guess I have to defer to the previous comment on proper usage ...
yes indeed; my answer is a complement; not a replacement of the answer of @socowi :)
I appreciate your help

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.