Mkbootfs writing to stdout in bash script

The shell does these and only these things to an unquoted $VARIABLE:

  • Splits into arguments on whitespace. (Technically, it splits on any character in the IFS variable, which you can alter at need.)
  • As a side effect, flattens whitespace. A variable containing " a b c" will become the arguments a, b, and c without leading, trailing, or any extra spaces.
  • Expand wildcards like * and ? from each argument into filenames. You can disable this if unwanted via set -f , and re-enable with set +f

It will not parse anything else. Not quotes, not variables, not backticks, not redirection. It simply takes them as literal parts of the string. It was giving mkbootfs the string > as an argument.

Take a look:

$ echo 'asdf'

asdf

$ VAR="echo 'asdf'"
$ $VAR

'asdf'

$

Imagine that you had to escape the > character every time you actually wanted to print that letter. How many special cases would there be? Should escaping happen before it gets in the string or after? Does the string need an actual \ inside it or not? How many? What if you want an actual backslash? How many different things would you end up needing to escape to get them into a string? There'd be so many weird special cases that BASH code would start looking like Perl.

Now imagine your program reads a string from the keyboard, and someone decides to be clever by typing in `rm -Rf ~/`. Should the shell blindly execute that shell statement next time you use that variable? Keeping your code secure from unintended situations would be near impossible.

For these and other reasons, the Bourne shell is very strict and consistent about when substitution happens. If it's not in the file, it doesn't do it, unless you force it with eval.

eval will blindly substitute this way, and for this reason, must be used with extreme care.

1 Like

Thank you for the basic explanation. I know well about the the splitting at spaces for unquoted variables, but thought that single quoting stops this.

Even single quoting won't make it work

#!/bin/bash -xv
CMD_LINE1='/root/Desktop/build_cm10/android_cm-10.1/system/out/host/linux-x86/bin/mkbootfs /root/Desktop/build_cm10/android_cm-10.1/system/out/target/product/n7100/recovery/root > /root/Desktop/build_cm10/android_cm-10.1/system/out/target/product/n7100/ramdisk-recovery.cpio'
$CMD_LINE1

Now, understanding that be it quoted or unquoted, every segment is passed as an argument makes things clear and evident

Thank you

Single-quoting a > will not let the shell parse it later. The quotes cease to exist when the string is stored, they only tell the shell what to do with a string right then, they don't change the meaning later. Using single quotes versus double quotes tells the shell whether to attempt anything like substituting variables right now and no other time.

Be it single or double quoted, if you force a string to contain actual quote, pipe, redirection, backtick, or dollar-sign characters, the shell will understand them to be literal characters, not anything with meaning.

In other words, storing shell statements inside strings continues to be a poor idea no matter how you cut it. There is not a mysterious "right way" to do this that we are hiding from you. If you explained your intent we could probably show you a better way to accomplish the result you want, but it would be done in a completely different manner.

1 Like

Thank you
It is ok, I got it.

I never did such a thing. Was debugging quickly my script and wanted to test the whole line without a second thought. Once it failed, I did not know that the shell will always understand this as literal characters. Now it is really clear.

This is the portion I wanted to achieve since you asked:

DEVICE_ID=$1
OUT_DIR="/output/path"

# correct way to run my command:
"$OUT_DIR"/utils/mkbootfs "$OUT_DIR"/"$DEVICE_ID"/ramdisk > "$OUT_DIR"/"$DEVICE_ID"/recovery-image.cpio

If you have another opinion about it, you are welcome

I have an opinion. :slight_smile:

Do not put double quotes around the variables, because:

1) Not needed. Makes it harder to read.
2) Nobody else writes it that way.
3) Confusing to others. They waste time trying to figure out why.

Compare:

"$OUT_DIR"/utils/mkbootfs "$OUT_DIR"/"$DEVICE_ID"/ramdisk > "$OUT_DIR"/"$DEVICE_ID"/recovery-image.cpio
$OUT_DIR/utils/mkbootfs $OUT_DIR/$DEVICE_ID/ramdisk > $OUT_DIR/$DEVICE_ID/recovery-image.cpio

yes, just a habit to limit errors if spaces under some functions
Thank you

You're right. I never put spaces in file names, instead using underscore or dash instead, because using spaces introduces little complexities like this. But you're right to use those double quotes if any chance of those spaces in the names.

Yes, mainly to run commands, using quotes is important in my opinion
To assign variables, it can be optional in some cases