0

I wrote some script:

#!/bin/sh

dialog --menu \
"Please select a partition from the following list to use for your \
root (/) Linux partition." 13 70 3 \
"/dev/hda2" "Linux native 30724312K" "/dev/hda4" "Linux native 506047K"


DISKS='"disk1" "50 Gb" "disk2" "100 Gb"'

dialog --menu \
"Please select a partition from the following list to use for your \
root (/) Linux partition." 13 70 3 \
$DISKS

The first call looks good. enter image description here

The second call looks bad. enter image description here

I need to transmit information about the drives through the variable. Please tell me why the second version of the call does not work as expected?

Community
  • 1
  • 1
Abradox
  • 117
  • 1
  • 7

1 Answers1

3

Let's ask shellcheck:

$ shellcheck myscript

In myscript line 9:
DISKS='"disk1" "50 Gb" "disk2" "100 Gb"'
      ^-- SC2089: Quotes/backslashes will be treated literally. Use an array.


In myscript line 14:
$DISKS
^-- SC2090: Quotes/backslashes in this variable will not be respected.

The detailed error page offers an explanation:


Bash does not interpret data as code. Consider almost any other languages, such as Python:

print 1+1   # prints 2
a="1+1"
print a     # prints 1+1, not 2

Here, 1+1 is Python syntax for adding numbers. However, passing a literal string containing this expression does not cause Python to interpret it, see the + and produce the calculated result.

Similarly, "My File.txt" is Bash syntax for a single word with a space in it. However, passing a literal string containing this expression does not cause Bash to interpret it, see the quotes and produce the tokenized result.

The solution is to use an array instead, whenever possible.


Ok, let's try that:

#!/bin/bash
DISKS=("disk1" "50 Gb" "disk2" "100 Gb")

dialog --menu \
"Please select a partition from the following list to use for your \
root (/) Linux partition." 13 70 3 \
"${DISKS[@]}"

This works.

However, this is a bash specific solution. If you want it to work for sh, in this case, you can pick a delimiter other than whitespace by setting the Internal Field Separator:

#!/bin/sh
IFS=":" # Split on colons
set -f  # Prevent globbing
DISKS='disk1:50 Gb:disk2:100 Gb'
dialog --menu \
"Please select a partition from the following list to use for your \
root (/) Linux partition." 13 70 3 \
$DISKS

This also works as expected. If your script is longer than this, you'd want to set IFS back to its original value.

that other guy
  • 116,971
  • 11
  • 170
  • 194