2

Assuming I want to run commnand stored inside the variable with nullglob turned on. For example:

shopt -s nullglob
a="echo [foo]bar"
${a}

This gives me an empty output due to the nullglob option of course, but I want the following output (which I am not able to get):

[foo]bar

I tried escaping [] with \ but that just gives me:

\[foo\]bar

What is the correct way of escaping it?

EDIT (clarification with some context):

I have a script like this:

shopt -s nullglob
for file in tmp/*.pdb; do
    base="$(basename ${file} .pdb)"
    a="command --option [${base}]foo"
    ${a}
done
shopt -u nullglob

What I wanted to achieve is to run command for each file with an option which has [] as ordinary characters (without any matching). The nullglob here was used just for the for loop.

That is if "tmp" contains "a.pdb" run:

command --option '[a]foo'

and nothing if no such file is present.

In a meantime I figured out that moving "shopt -u nullglob" as the first command in the for loop seems to solve the problem. However, I am curious if I can somehow escape the [] even with nullglob.

4
  • Sorry, my bad. I'd misunderstood. Could you clarify what output you expect if i) there is a file matching [foo]bar and ii) if there isn't?
    – terdon
    Commented Sep 17, 2015 at 14:51
  • Also, you seem to be attempting to recreate the behavior of the shell without nullglob. Why not just unset nullglob? What am I missing?
    – terdon
    Commented Sep 17, 2015 at 14:59
  • @terdon I guess the original question wasn't clear at all, sorry. :-) I added some clarification.
    – krab1k
    Commented Sep 17, 2015 at 15:25
  • Ah, yes, that makes more sense :) See updated answer, does that help?
    – terdon
    Commented Sep 17, 2015 at 15:39

2 Answers 2

3

First, read I'm trying to put a command in a variable, but the complex cases always fail!.

Then, define a function:

a () {
    echo "[foo]bar"
}

For your script, there is no reason to put the command in a variable first anway; just run the command.

shopt -s nullglob
for file in tmp/*.pdb; do
    base="$(basename ${file} .pdb)"
    command --option "[${base}]foo"
done
shopt -u nullglob

If you must store something in variables, separate the command from its options, and use an array to hold the options.

shopt -s nullglob
cmd=command
for file in tmp/*.pdb; do
    base="$(basename ${file} .pdb)"
    options=( --option "[${base}]foo" )
    "$cmd" "${options[@]}"
done
shopt -u nullglob
1
  • The purpose of having all of this in a variable was to write it to the log if command fails. However, since command is the always the same, logging the options is sufficient (which I didn't realize earlier) and the array approach you mentioned works great. Thanks!
    – krab1k
    Commented Sep 18, 2015 at 5:19
1

I don't understand why you're saving the command as a variable. Why not do something like what I show below and avoid the problem?

shopt -s nullglob
for file in tmp/*.pdb; do
    base="$(basename ${file} .pdb)"
    command --option "[${base}]foo"
done
shopt -u nullglob

Alternatively, if you need the command in a variable for other reasons, you could remove the nullglob and just make sure that files exist before running the command:

for file in tmp/*.pdb; do
  if [ -e "$file" ]; then
        base="$(basename ${file} .pdb)"
        a="command --option [${base}]foo"
        ${a}
done

It's rarely a good idea to save commands as variables. Another approach would be to save the options as variables instead:

shopt -s nullglob
for file in tmp/*.pdb; do
    base="$(basename ${file} .pdb)"
    a="--option [${base}]foo"
    command "$a"
done
shopt -u nullglob
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .