-1

i have the following two lines in a batch script

iperf_options=" -O 10 -V -i 10 --get-server-output -P " $streams
$iperf_options=$iperf_options $proto

and

$streams = 2
$proto = -u 

but when i run this i get the following error.

./bandwidth: line 116: -O: command not found

I am simply trying to wrote a string and then append it to a variable so why does it throw the error on the -O?

I have looked about the web but i jsut seem to find stuff about spaces around the "="

any help greatfully recived.

Thankyou

code block to show error

proto=-u
streams=2
iperf_options=" -O 10 -V -i 10 --get-server-output -P " $streams
$iperf_options=$iperf_options $proto

running this will give this out put

./test
./test: line 3: 2: command not found
./test: line 4: =: command not found
DevilWAH
  • 2,553
  • 13
  • 41
  • 57
  • sorry, but neither the variable assignments nor the error message look anything like `batch-file`. Did you mean `bash`? – Stephan Feb 28 '21 at 21:22
  • Neither of your two lines are commands understood by the command interpreter on MS-DOS, IBM OS/2, or Microsoft Windows systems. Did you make any attempt at reading the description for the [[tag:batch-file]] tag, before assigning it to your question? – Compo Feb 28 '21 at 21:25
  • Sorry that me being stupid you are right i meant to type bash. – DevilWAH Feb 28 '21 at 21:30
  • in bash you have to omit space between variable and value, it means instead of `a = 110` you have to write `a=110` another thing is, when you wanna declare a variable you don't have to use `$` but when you call it you have, for example `a=110` and call it like this `echo $a`, good luck ! – Freeman Feb 28 '21 at 21:37
  • so freeman in the above there is no space. or is it the space with in the string " -O... considered a space. as it lets me decare it with it. its the $iperf_options=$iperf_options... that is causign the issue – DevilWAH Feb 28 '21 at 21:40
  • may I see your whole code ? – Freeman Feb 28 '21 at 21:41
  • proto = -u streams = 2 iperf_options=" -O 10 -V -i 10 --get-server-output -P " $streams $iperf_options=$iperf_options $proto – DevilWAH Feb 28 '21 at 21:44
  • No, we need more than that. – Benjamin W. Feb 28 '21 at 21:48
  • No Ben those 4 lines will throw the error "proto=-u", "streams=2" folowed by the two lines in the original post – DevilWAH Feb 28 '21 at 21:50
  • Added the snip above that you can run to test asa bash script – DevilWAH Feb 28 '21 at 21:52
  • See [BashFAQ #50](https://mywiki.wooledge.org/BashFAQ/050) re: why string-type variables should not be used to store commands, and what to do instead. – Charles Duffy Feb 28 '21 at 21:54

1 Answers1

2

There are two main mistakes here, in a variety of combinations.

  1. Use $ to get the value of a variable, never when setting the variable (or changing its properties):

    $var=value    # Bad
    var=value     # Good
    var=$othervar # Also good
    
  2. Spaces are critical delimiters in shell syntax; adding (or removing) them can change the meaning of a command in unexpected ways:

    var = value    # Runs `var` as a command, passing "=" and "value" as arguments
    var=val1 val2  # Runs `val2` as a command, with var=val1 set in its environment
    
    var="val1 val2"  # Sets `var1` to `val1 val2`
    

    So, in this command:

    iperf_options=" -O 10 -V -i 10 --get-server-output -P " $streams
    

    The space between iperf_options="..." and $streams means that it'll expand $streams and try to run it as a command (with iperf_options set in its environment). You want something like:

    iperf_options=" -O 10 -V -i 10 --get-server-output -P $streams"
    

    Here, since $streams is part of the double-quoted string, it'll be expanded (variable expand inside double-quotes, but not in single-quoted), and its value included in the value assigned to iperf_options.

There's actually a third mistake (or at least dubious scripting practice): building lists of options as simple string variables. This works in simple cases, but fails when things get complex. If you're using a shell that supports arrays (e.g. bash, ksh, zsh, etc, but not dash), it's better to use those instead, and store each option/argument as a separate array element, and then expand the array with "${arrayname[@]}" to get all of the elements out intact (yes, all those quotes, braces, brackets, etc are actually needed).

proto="-u"    # If this'll always have exactly one value, plain string is ok
streams=2     # Same here
iperf_options=(-O 10 -V -i 10 --get-server-output -P "$streams")
iperf_options=("${iperf_options[@]}" "$proto")
# ...
iperf "${iperf_options[@]}"

Finally, I recommend shellcheck.net to sanity-check your scripts for common mistakes. A warning, though: it won't catch all errors, since it doesn't know your intent. For instance, if it sees var=val1 val2 it'll assume you meant to run val2 as a command and won't flag it as a mistake.

Gordon Davisson
  • 118,432
  • 16
  • 123
  • 151
  • Ahh right, thank you. I understood the space between the var=value must not exist, but i can see it was after the quoted string i was adding one as well. – DevilWAH Feb 28 '21 at 21:56
  • Oh and thanks for the headup about the site to check it, it will be added to the bookmarks next to the regex checker :) – DevilWAH Feb 28 '21 at 21:58
  • to check changed it to iperf_options=" -O 10.... $streams $proto" but will swap to an array later. Thanks for taking the time to answer this and for the detailed explication. – DevilWAH Feb 28 '21 at 22:07
  • @DevilWAH That'll work as long as none of the options/arguments you're storing contain whitespace, wildcards, quotes, escapes, etc -- basically as long as they're just straight plaintext with no shell syntax separated by spaces, you can get away with using a plain string. – Gordon Davisson Feb 28 '21 at 22:09