2

I have the following test.cpp c++ program

#include <stdio.h>
#include <stdlib.h>
#include <iostream>

using namespace std;

int main()
{
    float a,b,c;
    cout<<"Give 1st number";
    cin>>a;
    cout<<"Give 2nd number:";
    cin>>b;

    c=a+b;
    cout<<"\n"<<a<<"+"<<b<<"="<<c<<endl;

return 0;
}

and I want to create a shell script which gives the input variables. I know how to pass one variable, and I would like to know if there is a way to pass 2 variables... like the following test.sh file which is not working

#!/bin/bash

g++ test.cpp -o testexe
chmod +x testexe

a=1
b=2

./testexe <<< $a $b
6
  • 2
    You mean like echo $a $b | ./testexe? Commented Apr 29, 2015 at 15:12
  • 1
    ./testexe <<<$'$a\n$b\n' or similar should work too $'' needed to get a literal newline in there (for single line demonstration) but could be done over multiple lines otherwise. Commented Apr 29, 2015 at 15:14
  • Since this is about the shell part and not the C++ part you might want to loose the c++ tag. Or else some C++ guy might read the question and give a lengthy wail about that code (repeated includes, unnecessary includes, C-header includes, questionable using directive, weird indentation, Missingwhitespacetomakeyourcodeunreadable,...) Commented Apr 29, 2015 at 15:19
  • 1
    @EtanReisner, $'$a\n$b\n' won't expand the variables. Commented Apr 29, 2015 at 15:25
  • 1
    @CharlesDuffy Good point. I'd assumed it would (I basically never use it) since it expands the escapes. So <<"$a"$'\n'"$b" would be necessary for single-line usage (assuming the input needs to be newline split). Commented Apr 29, 2015 at 15:29

3 Answers 3

3

To be compatible with not just bash, but also /bin/sh -- while avoiding pipeline overhead -- use a heredoc:

./testexe <<EOF
$a
$b
EOF

If you don't care about pipeline overhead (and still maintaining /bin/sh compatibility, which any answer using <<< lacks):

printf '%s\n' "$a" "$b" |  ./testexe

If you don't care about /bin/sh compatibility:

./testexe <<<"$a"$'\n'"$b"
Sign up to request clarification or add additional context in comments.

Comments

1

You should change your C++ program and script as follows :

int main(int argc, const char*argv[])
{
    float a,b,c;
    a=std::stof(argv[1]);
    b=std::stof(argv[2]);
    c=a+b;
    cout<<"\n"<<a<<"+"<<b<<"="<<c<<endl;
    return 0;
}


#!/bin/bash

g++ test.cpp -o testexe
chmod +x testexe

a=1
b=2

./testexe  $a $b

7 Comments

Sidesteps the question rather than answering it, no?
` test.cpp: In function ‘int main(int, char**)’: test.cpp:12:6: error: cannot convert ‘char*’ to ‘float’ in assignment a=argv[1]; ^ test.cpp:13:6: error: cannot convert ‘char*’ to ‘float’ in assignment b=argv[2]; ^ Give 1st number:^C `
@OrestisKotsas, ...to be clear, by the way -- sidestepping the question is the right thing to do. You should take arguments off of the command line, not stdin, when you can.
@ Charles Duffy sidestepping the question ? What you mean? Forgive me, but my english is not in a very good level... This is an example of the code that I am dealing with, and it is not easy to change the structure of the code. I just wanted the basic idea...
@OrestisKotsas, "sidestepping the question", meaning doing something that avoids the problem you asked about, rather than actually solving the literal problem as asked. In this case, reading arguments off the command line (from the argv array) is better practice than reading them from stdin, but you asked specifically about stdin -- so a direct answer would involve stdin; this one tries to show you a better practice instead (though it's buggy).
|
1

Like this:

echo "$a $b" | ./testexe

Or:

arr=("$a" "$b")
./testexe <<< "${arr[*]}"

Or:

./testexe <<< "$a $b"

Or:

./testexe <<< "$a"$' '"$b"

If you want it to work for string variables too (with white spaces), then use new line as separator between two variables instead of a single space.

Ex:

echo "$a"$'\n'"$b" | ./testexe

16 Comments

echo $a $b works here, where values are guaranteed to be numbers (unless IFS is set to a value containing digits in those numbers, in which case this would break without quotes), but it's an iffy practice in general -- arguments get string-split and glob-expanded. Let's say you were passing in a filename rather than a number; if that name were something like *** HELLO WORLD ***.txt, then the first set of *s would be glob-expanded, and replaced with filenames from the current directory, while the second set would be replaced with a list of text file names.
Thus, echo "$a $b" is a safer replacement; likewise, printf '%s %s\n' "$a" "$b".
The array suggestion currently given doesn't fix the globbing problems, since you're still doing unquoted assignments when putting values into the array, and has potential forward-compatibility issues since the semantics of ${foo[@]} are undefined (and thus, open to change) when treated as a scalar value (you should use "${foo[*]}" in that case).
So: arr=( "$a" "$b" ); ./testexe <<<"${arr[*]}" would be more correct.
@Jahid, ${foo[*]} combines an array into a string by separating each element by the first character of IFS, or a space by default. By contrast, "${foo[@]}" emits the array as separate elements when quoted. When it's not quoted, or in a scenario where only a single string is usable, its behavior is more ambiguous, which is why "${foo[*]}" is preferable in those cases (but only those cases).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.