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 Sep 17 '15 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 Sep 17 '15 at 14:59
  • @terdon I guess the original question wasn't clear at all, sorry. :-) I added some clarification. – krab1k Sep 17 '15 at 15:25
  • Ah, yes, that makes more sense :) See updated answer, does that help? – terdon Sep 17 '15 at 15:39
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 Sep 18 '15 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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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