Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I have a command stored in a variable. Let's pretend the variable $i has the value:

cat -nT index.php |grep 'someregex'

When I try to execute the above variable by typing $i it fails because the shell attempts to execute the entire variable as one command. I also tried using eval($i) and putting $i in backticks.

How can I make the shell execute $i as if it were a command? And why isn't it working the same as.

$i='echo hi'; $i

Is it because I had to sort of hack in the single quotes? (Because you can't nest them.) Currently my solution is

echo $i > /foo;  . /foo

But I don't want to have create a file just for this, only to delete it later.

What I mean by "I hacked in the single quotes is I did:

$i='cat index.php | grep -P '"'"'MYREGEXHERE'"'"
share|improve this question
4  
The question is, why is the command stored in a variable in the first place? You'd be better off assembling the command when you run it, storing the option arguments in variables or in an array. Can you show the entire script you have? –  slhck Nov 24 '13 at 8:49

3 Answers 3

Short answer: see BashAQ #50:I'm trying to put a command in a variable, but the complex cases always fail!.

Long answer: it's because of the order in which bash parses the command line. Specifically, it looks for things like pipes and redirects before it expands variable values, and doesn't go back and re-look for pipes etc in the expanded values. Essentially, variables get substituted about halfway through the parsing process, so the value only gets halfway-parsed before being executed.

In order to solve this, you need to answer @slhck's question: why is the command stored in a variable in the first place? What is the actual problem you're trying to solve? Depending on the actual goal, there are a number of possible solutions:

  • Don't store it in a variable, just execute it directly. Storing commands for later use is tricky, and if you don't really need to, just don't.

  • Use a function instead of a variable. That's what they're for, after all:

    i() { cat -nT index.php |grep 'someregex'; }
    i
    

    The main disadvantage of this is that you can't create the function dynamically -- you can't conditionally include or exclude code from the function (although the function itself can have conditional elements that're selected when it's executed).

  • Use eval. This should be considered a last resort, since it's easy to get unexpected behavior. It essentially runs the command through another full parsing pass, so all pipes etc get their full meaning -- but it also means that parts of the command you thought were just data will also get parsed and maybe executed. Filenames that contain shell metacharacters (pipe, semicolon, quote/apostrophe, etc) can have weird and sometimes dangerous effects. If you do use eval, at least double-quote the string, otherwise its contents essentially get parsed one-and-a-half times, with even weirder results.

    i="cat -nT index.php |grep 'someregex'"
    eval "$i"
    

EDIT: Another standard store-a-command-in-a-variable approach is to use an array instead of a simple variable. This allows you store a command with complex arguments (e.g. containing spaces) without trouble, but won't store things like pipes and redirects. So, the array approach won't be useful in this particular case.

share|improve this answer

This should just work:

a="cat -nT index.php |grep 'someregex'"
eval "$a"

Beware that eval introduces potential vulnerabilities and unexpected behavior situations so must be used, if ever, with extra care.

share|improve this answer
    
If you do use eval, you really need to use double-quotes (eval "$i") to avoid extra-extra-weird effects. For example, try this with a="cat -nT index.php |grep ' .* '" (i.e. the regex should match two spaces with any sequence of characters between them) and see what actually happens. For extra credit, explain why it happens. –  Gordon Davisson Nov 24 '13 at 20:59
    
@GordonDavisson double quotes added. –  jlliagre Nov 24 '13 at 21:16

When declaring the variable, you shouldn't use the dollar sign as a prefix.

Try this:

i='echo hi'; $i
share|improve this answer
    
That's correct, but it's not an answer to the OP's question, really. –  slhck Nov 24 '13 at 9:29

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.