How to write a bash file to compile and execute a c++ program [closed]











up vote
-1
down vote

favorite












I'm practically done with my project, all I need now is to write a bash script that should compile and execute the program. My instructions are that we should provide a script that should compile the program and the instructor should be able to run the program by typing in Project1 Value1 Value2. I'm kinda lost on this one, so any help would be appreciated.



I have tried to compile the program by running this script



#!/bin/bash
echo $1
echo $2
g++ -std=c++11 Project2.cpp -lpthread -o project1
./project1 $1 $2


Edit



#!/bin/bash
g++ -std=c++11 Project2.cpp -lpthread -o project1


I thought about it a bit more, and I think my second version is closer to what I would like my script to do. Except I was hoping to be able to execute the program without using ./ if possible.










share|improve this question















closed as unclear what you're asking by tripleee, eyllanesc, sideshowbarker, Pearly Spencer, Machavity Nov 14 at 13:02


Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.















  • What problems are you having exactly? For robustness you might want to fix the things that shellcheck.net reports.
    – tripleee
    Nov 14 at 6:13










  • I think my main problem at the moment is my lack of experience with writing a script to compile a program. Now that I think about it, I think I'm closer to my solution. I was wondering if it would be possible to compile a program and run it without using ./
    – random_coder
    Nov 14 at 6:15










  • Not really no. That would require you to have the current directory in the PATH, which is generally considered a very bad idea
    – tripleee
    Nov 14 at 6:19










  • For your own convenience you could declare a function like p1 () { ./Project1 "$@"; } in your interactive shell and then use the shorthand p1 instead of typing out the full path.
    – tripleee
    Nov 14 at 6:20












  • So my best option would be to use my second version of the script and simply run it by using ./Project1 value1 value2, correct?
    – random_coder
    Nov 14 at 6:21















up vote
-1
down vote

favorite












I'm practically done with my project, all I need now is to write a bash script that should compile and execute the program. My instructions are that we should provide a script that should compile the program and the instructor should be able to run the program by typing in Project1 Value1 Value2. I'm kinda lost on this one, so any help would be appreciated.



I have tried to compile the program by running this script



#!/bin/bash
echo $1
echo $2
g++ -std=c++11 Project2.cpp -lpthread -o project1
./project1 $1 $2


Edit



#!/bin/bash
g++ -std=c++11 Project2.cpp -lpthread -o project1


I thought about it a bit more, and I think my second version is closer to what I would like my script to do. Except I was hoping to be able to execute the program without using ./ if possible.










share|improve this question















closed as unclear what you're asking by tripleee, eyllanesc, sideshowbarker, Pearly Spencer, Machavity Nov 14 at 13:02


Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.















  • What problems are you having exactly? For robustness you might want to fix the things that shellcheck.net reports.
    – tripleee
    Nov 14 at 6:13










  • I think my main problem at the moment is my lack of experience with writing a script to compile a program. Now that I think about it, I think I'm closer to my solution. I was wondering if it would be possible to compile a program and run it without using ./
    – random_coder
    Nov 14 at 6:15










  • Not really no. That would require you to have the current directory in the PATH, which is generally considered a very bad idea
    – tripleee
    Nov 14 at 6:19










  • For your own convenience you could declare a function like p1 () { ./Project1 "$@"; } in your interactive shell and then use the shorthand p1 instead of typing out the full path.
    – tripleee
    Nov 14 at 6:20












  • So my best option would be to use my second version of the script and simply run it by using ./Project1 value1 value2, correct?
    – random_coder
    Nov 14 at 6:21













up vote
-1
down vote

favorite









up vote
-1
down vote

favorite











I'm practically done with my project, all I need now is to write a bash script that should compile and execute the program. My instructions are that we should provide a script that should compile the program and the instructor should be able to run the program by typing in Project1 Value1 Value2. I'm kinda lost on this one, so any help would be appreciated.



I have tried to compile the program by running this script



#!/bin/bash
echo $1
echo $2
g++ -std=c++11 Project2.cpp -lpthread -o project1
./project1 $1 $2


Edit



#!/bin/bash
g++ -std=c++11 Project2.cpp -lpthread -o project1


I thought about it a bit more, and I think my second version is closer to what I would like my script to do. Except I was hoping to be able to execute the program without using ./ if possible.










share|improve this question















I'm practically done with my project, all I need now is to write a bash script that should compile and execute the program. My instructions are that we should provide a script that should compile the program and the instructor should be able to run the program by typing in Project1 Value1 Value2. I'm kinda lost on this one, so any help would be appreciated.



I have tried to compile the program by running this script



#!/bin/bash
echo $1
echo $2
g++ -std=c++11 Project2.cpp -lpthread -o project1
./project1 $1 $2


Edit



#!/bin/bash
g++ -std=c++11 Project2.cpp -lpthread -o project1


I thought about it a bit more, and I think my second version is closer to what I would like my script to do. Except I was hoping to be able to execute the program without using ./ if possible.







bash






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 14 at 6:17

























asked Nov 14 at 6:05









random_coder

132




132




closed as unclear what you're asking by tripleee, eyllanesc, sideshowbarker, Pearly Spencer, Machavity Nov 14 at 13:02


Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.






closed as unclear what you're asking by tripleee, eyllanesc, sideshowbarker, Pearly Spencer, Machavity Nov 14 at 13:02


Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.














  • What problems are you having exactly? For robustness you might want to fix the things that shellcheck.net reports.
    – tripleee
    Nov 14 at 6:13










  • I think my main problem at the moment is my lack of experience with writing a script to compile a program. Now that I think about it, I think I'm closer to my solution. I was wondering if it would be possible to compile a program and run it without using ./
    – random_coder
    Nov 14 at 6:15










  • Not really no. That would require you to have the current directory in the PATH, which is generally considered a very bad idea
    – tripleee
    Nov 14 at 6:19










  • For your own convenience you could declare a function like p1 () { ./Project1 "$@"; } in your interactive shell and then use the shorthand p1 instead of typing out the full path.
    – tripleee
    Nov 14 at 6:20












  • So my best option would be to use my second version of the script and simply run it by using ./Project1 value1 value2, correct?
    – random_coder
    Nov 14 at 6:21


















  • What problems are you having exactly? For robustness you might want to fix the things that shellcheck.net reports.
    – tripleee
    Nov 14 at 6:13










  • I think my main problem at the moment is my lack of experience with writing a script to compile a program. Now that I think about it, I think I'm closer to my solution. I was wondering if it would be possible to compile a program and run it without using ./
    – random_coder
    Nov 14 at 6:15










  • Not really no. That would require you to have the current directory in the PATH, which is generally considered a very bad idea
    – tripleee
    Nov 14 at 6:19










  • For your own convenience you could declare a function like p1 () { ./Project1 "$@"; } in your interactive shell and then use the shorthand p1 instead of typing out the full path.
    – tripleee
    Nov 14 at 6:20












  • So my best option would be to use my second version of the script and simply run it by using ./Project1 value1 value2, correct?
    – random_coder
    Nov 14 at 6:21
















What problems are you having exactly? For robustness you might want to fix the things that shellcheck.net reports.
– tripleee
Nov 14 at 6:13




What problems are you having exactly? For robustness you might want to fix the things that shellcheck.net reports.
– tripleee
Nov 14 at 6:13












I think my main problem at the moment is my lack of experience with writing a script to compile a program. Now that I think about it, I think I'm closer to my solution. I was wondering if it would be possible to compile a program and run it without using ./
– random_coder
Nov 14 at 6:15




I think my main problem at the moment is my lack of experience with writing a script to compile a program. Now that I think about it, I think I'm closer to my solution. I was wondering if it would be possible to compile a program and run it without using ./
– random_coder
Nov 14 at 6:15












Not really no. That would require you to have the current directory in the PATH, which is generally considered a very bad idea
– tripleee
Nov 14 at 6:19




Not really no. That would require you to have the current directory in the PATH, which is generally considered a very bad idea
– tripleee
Nov 14 at 6:19












For your own convenience you could declare a function like p1 () { ./Project1 "$@"; } in your interactive shell and then use the shorthand p1 instead of typing out the full path.
– tripleee
Nov 14 at 6:20






For your own convenience you could declare a function like p1 () { ./Project1 "$@"; } in your interactive shell and then use the shorthand p1 instead of typing out the full path.
– tripleee
Nov 14 at 6:20














So my best option would be to use my second version of the script and simply run it by using ./Project1 value1 value2, correct?
– random_coder
Nov 14 at 6:21




So my best option would be to use my second version of the script and simply run it by using ./Project1 value1 value2, correct?
– random_coder
Nov 14 at 6:21












2 Answers
2






active

oldest

votes

















up vote
0
down vote



accepted










You have struggled for a few hours and put something together, but what happens if the compilation fails? What happens if there are no arguments? What happens if there are 4 arguments for the program?



When writing a script, or a program, the most important thing you can do is validate every necessary step! If you are expecting input, validate you received it. Once you have the input, validate it is what your expected. Is it a value within the usable range? Is it a filename that meets my requirements? Does it exist? Did my compile succeed or fail? Do I try and execute the program?



All of these need to be addressed. Otherwise, your script (or program) will stray off on some undefined path.



Bash provides a wealth of conditional expressions that can be used with test (or [...]) or using the bash [[...]] operator. See Bash Manual - 6.4 Bash Conditional Expressions. Make use of the language features to make your code robust.



Bash provides a wealth of string handling features through parameter expansions Bash Manual - 3.5.3 Shell Parameter Expansion, use them to check the extension to make sure it is c, cpp or c++



Putting those features together with a few if...then...fi statements will make your script much more reliable -- and actually do what it is you are trying to do.



The following short script takes arguments (bash Positional Parameters) requiring that at least the filename to compile be provided, and passing any additional arguments to the compiled program as command line arguments with ${@:2} (all bash positional parameters beginning with the 2nd one)



#!/bin/bash

if [ -z "$1" ] ## validate at least one argument given
then
printf "error: insufficient argumentsn" >&2
printf "usage: %s file.cpp [args]n" "${0##*/}" >&2
exit 1
fi

if [ ! -r "$1" ] ## validate file is readable
then
printf "error: file not found '%s'n" "$1" >&2
exit 1
fi

src="$1" ## give source file a handy name

## check the source file ends in '.c', '.cpp' or '.c++'
if [ "${src##*.}" != 'c' -a "${src##*.}" != 'cpp' -a "${src##*.}" != 'c++' ]
then
printf "error: first argument not a c/c++ filen" >&2
exit 1
fi

ext="${src##*.}" ## save the extension

if [ "${#ext}" = 'c' ] ## check if ext is 'c' use gcc else use g++
then
## always enable compiler warnings, -Wall -Wextra -pedantic, minimum
# -Wshadow to catch shadowed variables, -Werror treat warnings as error
gcc -Wall -Wextra -pedantic -Wshadow -Werror
-std=c11 -O3 -o "${src%.*}" "$src"
else
g++ -Wall -Wextra -pedantic -Wshadow -Werror
-std=c++11 -O3 -o "${src%.*}" "$src"
fi

if [ $? -eq '0' ] ## check the compiler return, run only on success
then
./"${src%.*}" ${@:2}
else
printf "nAn error occurred, executable not callednn" >&2
fi


Now a couple of short examples to make sure it works:



#include <stdio.h>

int main (int argc, char **argv) {

const char *s = "hello c file.";

printf ("%sn", s);

for (int i = 1; i < argc; i++)
printf ("arg[%d]: %sn", i, argv[i]);
}


Example Use/Output



$ bash compilewargs.sh cfile.c foo bar baz
hello c file.
arg[1]: foo
arg[2]: bar
arg[3]: baz


For C++



#include <iostream>
#include <string>

int main (int argc, char **argv) {

std::string s = "hello cpp file.";

std::cout << s << 'n';

for (int i = 1; i < argc; i++)
std::cout << "arg[" << i << "]: " << argv[i] << 'n';
}


Example Use/Output



$ bash compilewargs.sh cppfile.cpp foo bar baz
hello cpp file.
arg[1]: foo
arg[2]: bar
arg[3]: baz


Does the error-handling work?



#include <stdio.h>

int main (void) {

const char *s = "hello c file.";

printf ("%sn", unknown);
}


Example Use/Output



$ bash compilewargs.sh cerrfile.c foo bar baz
cerrfile.c: In function ‘int main()’:
cerrfile.c:7:21: error: ‘unknown’ was not declared in this scope
printf ("%sn", unknown);
^
cerrfile.c:5:17: error: unused variable ‘s’ [-Werror=unused-variable]
const char *s = "hello c file.";
^
cc1plus: all warnings being treated as errors

An error occurred, executable not called


What about a file that doesn't exist?



$ bash compilewargs.sh myfile.c foo bar baz
error: file not found 'myfile.c'


What about a text (or any other non-c, cpp or c++) file?



$ bash compilewargs.sh compilewargs.sh foo bar baz
error: first argument not a c/c++ file


By taking the time to think though what the dumbest user you know could ever try and do with your script -- and protecting against it, you can write reasonably robust scripts that will save you grief. Look things over and let me know if you have further questions.






share|improve this answer





















  • I appreciate your detailed response. I had to turn in the first half of my project tonight, so I put something together that should hopefully work with no problems. I have very little experience when it comes to writing scripts so I was a little lost, but I plan on reading through all the resources provided to me to come up with a better script when the final project is due.
    – random_coder
    Nov 14 at 9:13










  • Just like any language, learn the basics first, and then slowly digest to remaining language features as you go. Be curious. Don't be afraid of man bash (it's a bit cryptic at first, but it is all there). Also, bookmark ShellCheck, Bash Guide, and Bash FAQ and Bash Pitfalls. Bash is an incredible shell - if you can think it -- you can probably do it in bash...
    – David C. Rankin
    Nov 14 at 9:19










  • Thank you for all the information. I can't believe I have not looked into writing bash scripts sooner. They look like fun, and I hope I can free up some time to practice in my spare time.
    – random_coder
    Nov 14 at 9:27


















up vote
0
down vote













I ended up figuring it out after a while.



#!/bin/bash
echo "Enter TP"
read TP
echo "Enter TC"
read TC
g++ -std=c++11 Project_1.cpp -lpthread -o Project_1
./Project_1 $TP $TC





share|improve this answer

















  • 1




    A read is fine, but your original thought of using command line arguments was much better. You can validate you receive the correct input with if [ -z "$1" -o -z "$2" ]; then printf "error: insufficient inputnusage: %s filename.[c,ccp]n" "${0##*/}"; exit 1; fi If the one argument is not given, the program will then warn and exits displaying the usage: ... information.
    – David C. Rankin
    Nov 14 at 7:22










  • You still need to quote your arguments. Again, feed your scripts to shellcheck.net
    – tripleee
    Nov 14 at 8:35










  • I appreciate all the feedback and I will definitely work on my script. This was my first time putting together a script so I wasn't sure on the best way to approach the problem. On top of this, I had to submit before midnight, so I put something together that should hopefully work with no problems until I can work on a better solution.
    – random_coder
    Nov 14 at 9:10


















2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
0
down vote



accepted










You have struggled for a few hours and put something together, but what happens if the compilation fails? What happens if there are no arguments? What happens if there are 4 arguments for the program?



When writing a script, or a program, the most important thing you can do is validate every necessary step! If you are expecting input, validate you received it. Once you have the input, validate it is what your expected. Is it a value within the usable range? Is it a filename that meets my requirements? Does it exist? Did my compile succeed or fail? Do I try and execute the program?



All of these need to be addressed. Otherwise, your script (or program) will stray off on some undefined path.



Bash provides a wealth of conditional expressions that can be used with test (or [...]) or using the bash [[...]] operator. See Bash Manual - 6.4 Bash Conditional Expressions. Make use of the language features to make your code robust.



Bash provides a wealth of string handling features through parameter expansions Bash Manual - 3.5.3 Shell Parameter Expansion, use them to check the extension to make sure it is c, cpp or c++



Putting those features together with a few if...then...fi statements will make your script much more reliable -- and actually do what it is you are trying to do.



The following short script takes arguments (bash Positional Parameters) requiring that at least the filename to compile be provided, and passing any additional arguments to the compiled program as command line arguments with ${@:2} (all bash positional parameters beginning with the 2nd one)



#!/bin/bash

if [ -z "$1" ] ## validate at least one argument given
then
printf "error: insufficient argumentsn" >&2
printf "usage: %s file.cpp [args]n" "${0##*/}" >&2
exit 1
fi

if [ ! -r "$1" ] ## validate file is readable
then
printf "error: file not found '%s'n" "$1" >&2
exit 1
fi

src="$1" ## give source file a handy name

## check the source file ends in '.c', '.cpp' or '.c++'
if [ "${src##*.}" != 'c' -a "${src##*.}" != 'cpp' -a "${src##*.}" != 'c++' ]
then
printf "error: first argument not a c/c++ filen" >&2
exit 1
fi

ext="${src##*.}" ## save the extension

if [ "${#ext}" = 'c' ] ## check if ext is 'c' use gcc else use g++
then
## always enable compiler warnings, -Wall -Wextra -pedantic, minimum
# -Wshadow to catch shadowed variables, -Werror treat warnings as error
gcc -Wall -Wextra -pedantic -Wshadow -Werror
-std=c11 -O3 -o "${src%.*}" "$src"
else
g++ -Wall -Wextra -pedantic -Wshadow -Werror
-std=c++11 -O3 -o "${src%.*}" "$src"
fi

if [ $? -eq '0' ] ## check the compiler return, run only on success
then
./"${src%.*}" ${@:2}
else
printf "nAn error occurred, executable not callednn" >&2
fi


Now a couple of short examples to make sure it works:



#include <stdio.h>

int main (int argc, char **argv) {

const char *s = "hello c file.";

printf ("%sn", s);

for (int i = 1; i < argc; i++)
printf ("arg[%d]: %sn", i, argv[i]);
}


Example Use/Output



$ bash compilewargs.sh cfile.c foo bar baz
hello c file.
arg[1]: foo
arg[2]: bar
arg[3]: baz


For C++



#include <iostream>
#include <string>

int main (int argc, char **argv) {

std::string s = "hello cpp file.";

std::cout << s << 'n';

for (int i = 1; i < argc; i++)
std::cout << "arg[" << i << "]: " << argv[i] << 'n';
}


Example Use/Output



$ bash compilewargs.sh cppfile.cpp foo bar baz
hello cpp file.
arg[1]: foo
arg[2]: bar
arg[3]: baz


Does the error-handling work?



#include <stdio.h>

int main (void) {

const char *s = "hello c file.";

printf ("%sn", unknown);
}


Example Use/Output



$ bash compilewargs.sh cerrfile.c foo bar baz
cerrfile.c: In function ‘int main()’:
cerrfile.c:7:21: error: ‘unknown’ was not declared in this scope
printf ("%sn", unknown);
^
cerrfile.c:5:17: error: unused variable ‘s’ [-Werror=unused-variable]
const char *s = "hello c file.";
^
cc1plus: all warnings being treated as errors

An error occurred, executable not called


What about a file that doesn't exist?



$ bash compilewargs.sh myfile.c foo bar baz
error: file not found 'myfile.c'


What about a text (or any other non-c, cpp or c++) file?



$ bash compilewargs.sh compilewargs.sh foo bar baz
error: first argument not a c/c++ file


By taking the time to think though what the dumbest user you know could ever try and do with your script -- and protecting against it, you can write reasonably robust scripts that will save you grief. Look things over and let me know if you have further questions.






share|improve this answer





















  • I appreciate your detailed response. I had to turn in the first half of my project tonight, so I put something together that should hopefully work with no problems. I have very little experience when it comes to writing scripts so I was a little lost, but I plan on reading through all the resources provided to me to come up with a better script when the final project is due.
    – random_coder
    Nov 14 at 9:13










  • Just like any language, learn the basics first, and then slowly digest to remaining language features as you go. Be curious. Don't be afraid of man bash (it's a bit cryptic at first, but it is all there). Also, bookmark ShellCheck, Bash Guide, and Bash FAQ and Bash Pitfalls. Bash is an incredible shell - if you can think it -- you can probably do it in bash...
    – David C. Rankin
    Nov 14 at 9:19










  • Thank you for all the information. I can't believe I have not looked into writing bash scripts sooner. They look like fun, and I hope I can free up some time to practice in my spare time.
    – random_coder
    Nov 14 at 9:27















up vote
0
down vote



accepted










You have struggled for a few hours and put something together, but what happens if the compilation fails? What happens if there are no arguments? What happens if there are 4 arguments for the program?



When writing a script, or a program, the most important thing you can do is validate every necessary step! If you are expecting input, validate you received it. Once you have the input, validate it is what your expected. Is it a value within the usable range? Is it a filename that meets my requirements? Does it exist? Did my compile succeed or fail? Do I try and execute the program?



All of these need to be addressed. Otherwise, your script (or program) will stray off on some undefined path.



Bash provides a wealth of conditional expressions that can be used with test (or [...]) or using the bash [[...]] operator. See Bash Manual - 6.4 Bash Conditional Expressions. Make use of the language features to make your code robust.



Bash provides a wealth of string handling features through parameter expansions Bash Manual - 3.5.3 Shell Parameter Expansion, use them to check the extension to make sure it is c, cpp or c++



Putting those features together with a few if...then...fi statements will make your script much more reliable -- and actually do what it is you are trying to do.



The following short script takes arguments (bash Positional Parameters) requiring that at least the filename to compile be provided, and passing any additional arguments to the compiled program as command line arguments with ${@:2} (all bash positional parameters beginning with the 2nd one)



#!/bin/bash

if [ -z "$1" ] ## validate at least one argument given
then
printf "error: insufficient argumentsn" >&2
printf "usage: %s file.cpp [args]n" "${0##*/}" >&2
exit 1
fi

if [ ! -r "$1" ] ## validate file is readable
then
printf "error: file not found '%s'n" "$1" >&2
exit 1
fi

src="$1" ## give source file a handy name

## check the source file ends in '.c', '.cpp' or '.c++'
if [ "${src##*.}" != 'c' -a "${src##*.}" != 'cpp' -a "${src##*.}" != 'c++' ]
then
printf "error: first argument not a c/c++ filen" >&2
exit 1
fi

ext="${src##*.}" ## save the extension

if [ "${#ext}" = 'c' ] ## check if ext is 'c' use gcc else use g++
then
## always enable compiler warnings, -Wall -Wextra -pedantic, minimum
# -Wshadow to catch shadowed variables, -Werror treat warnings as error
gcc -Wall -Wextra -pedantic -Wshadow -Werror
-std=c11 -O3 -o "${src%.*}" "$src"
else
g++ -Wall -Wextra -pedantic -Wshadow -Werror
-std=c++11 -O3 -o "${src%.*}" "$src"
fi

if [ $? -eq '0' ] ## check the compiler return, run only on success
then
./"${src%.*}" ${@:2}
else
printf "nAn error occurred, executable not callednn" >&2
fi


Now a couple of short examples to make sure it works:



#include <stdio.h>

int main (int argc, char **argv) {

const char *s = "hello c file.";

printf ("%sn", s);

for (int i = 1; i < argc; i++)
printf ("arg[%d]: %sn", i, argv[i]);
}


Example Use/Output



$ bash compilewargs.sh cfile.c foo bar baz
hello c file.
arg[1]: foo
arg[2]: bar
arg[3]: baz


For C++



#include <iostream>
#include <string>

int main (int argc, char **argv) {

std::string s = "hello cpp file.";

std::cout << s << 'n';

for (int i = 1; i < argc; i++)
std::cout << "arg[" << i << "]: " << argv[i] << 'n';
}


Example Use/Output



$ bash compilewargs.sh cppfile.cpp foo bar baz
hello cpp file.
arg[1]: foo
arg[2]: bar
arg[3]: baz


Does the error-handling work?



#include <stdio.h>

int main (void) {

const char *s = "hello c file.";

printf ("%sn", unknown);
}


Example Use/Output



$ bash compilewargs.sh cerrfile.c foo bar baz
cerrfile.c: In function ‘int main()’:
cerrfile.c:7:21: error: ‘unknown’ was not declared in this scope
printf ("%sn", unknown);
^
cerrfile.c:5:17: error: unused variable ‘s’ [-Werror=unused-variable]
const char *s = "hello c file.";
^
cc1plus: all warnings being treated as errors

An error occurred, executable not called


What about a file that doesn't exist?



$ bash compilewargs.sh myfile.c foo bar baz
error: file not found 'myfile.c'


What about a text (or any other non-c, cpp or c++) file?



$ bash compilewargs.sh compilewargs.sh foo bar baz
error: first argument not a c/c++ file


By taking the time to think though what the dumbest user you know could ever try and do with your script -- and protecting against it, you can write reasonably robust scripts that will save you grief. Look things over and let me know if you have further questions.






share|improve this answer





















  • I appreciate your detailed response. I had to turn in the first half of my project tonight, so I put something together that should hopefully work with no problems. I have very little experience when it comes to writing scripts so I was a little lost, but I plan on reading through all the resources provided to me to come up with a better script when the final project is due.
    – random_coder
    Nov 14 at 9:13










  • Just like any language, learn the basics first, and then slowly digest to remaining language features as you go. Be curious. Don't be afraid of man bash (it's a bit cryptic at first, but it is all there). Also, bookmark ShellCheck, Bash Guide, and Bash FAQ and Bash Pitfalls. Bash is an incredible shell - if you can think it -- you can probably do it in bash...
    – David C. Rankin
    Nov 14 at 9:19










  • Thank you for all the information. I can't believe I have not looked into writing bash scripts sooner. They look like fun, and I hope I can free up some time to practice in my spare time.
    – random_coder
    Nov 14 at 9:27













up vote
0
down vote



accepted







up vote
0
down vote



accepted






You have struggled for a few hours and put something together, but what happens if the compilation fails? What happens if there are no arguments? What happens if there are 4 arguments for the program?



When writing a script, or a program, the most important thing you can do is validate every necessary step! If you are expecting input, validate you received it. Once you have the input, validate it is what your expected. Is it a value within the usable range? Is it a filename that meets my requirements? Does it exist? Did my compile succeed or fail? Do I try and execute the program?



All of these need to be addressed. Otherwise, your script (or program) will stray off on some undefined path.



Bash provides a wealth of conditional expressions that can be used with test (or [...]) or using the bash [[...]] operator. See Bash Manual - 6.4 Bash Conditional Expressions. Make use of the language features to make your code robust.



Bash provides a wealth of string handling features through parameter expansions Bash Manual - 3.5.3 Shell Parameter Expansion, use them to check the extension to make sure it is c, cpp or c++



Putting those features together with a few if...then...fi statements will make your script much more reliable -- and actually do what it is you are trying to do.



The following short script takes arguments (bash Positional Parameters) requiring that at least the filename to compile be provided, and passing any additional arguments to the compiled program as command line arguments with ${@:2} (all bash positional parameters beginning with the 2nd one)



#!/bin/bash

if [ -z "$1" ] ## validate at least one argument given
then
printf "error: insufficient argumentsn" >&2
printf "usage: %s file.cpp [args]n" "${0##*/}" >&2
exit 1
fi

if [ ! -r "$1" ] ## validate file is readable
then
printf "error: file not found '%s'n" "$1" >&2
exit 1
fi

src="$1" ## give source file a handy name

## check the source file ends in '.c', '.cpp' or '.c++'
if [ "${src##*.}" != 'c' -a "${src##*.}" != 'cpp' -a "${src##*.}" != 'c++' ]
then
printf "error: first argument not a c/c++ filen" >&2
exit 1
fi

ext="${src##*.}" ## save the extension

if [ "${#ext}" = 'c' ] ## check if ext is 'c' use gcc else use g++
then
## always enable compiler warnings, -Wall -Wextra -pedantic, minimum
# -Wshadow to catch shadowed variables, -Werror treat warnings as error
gcc -Wall -Wextra -pedantic -Wshadow -Werror
-std=c11 -O3 -o "${src%.*}" "$src"
else
g++ -Wall -Wextra -pedantic -Wshadow -Werror
-std=c++11 -O3 -o "${src%.*}" "$src"
fi

if [ $? -eq '0' ] ## check the compiler return, run only on success
then
./"${src%.*}" ${@:2}
else
printf "nAn error occurred, executable not callednn" >&2
fi


Now a couple of short examples to make sure it works:



#include <stdio.h>

int main (int argc, char **argv) {

const char *s = "hello c file.";

printf ("%sn", s);

for (int i = 1; i < argc; i++)
printf ("arg[%d]: %sn", i, argv[i]);
}


Example Use/Output



$ bash compilewargs.sh cfile.c foo bar baz
hello c file.
arg[1]: foo
arg[2]: bar
arg[3]: baz


For C++



#include <iostream>
#include <string>

int main (int argc, char **argv) {

std::string s = "hello cpp file.";

std::cout << s << 'n';

for (int i = 1; i < argc; i++)
std::cout << "arg[" << i << "]: " << argv[i] << 'n';
}


Example Use/Output



$ bash compilewargs.sh cppfile.cpp foo bar baz
hello cpp file.
arg[1]: foo
arg[2]: bar
arg[3]: baz


Does the error-handling work?



#include <stdio.h>

int main (void) {

const char *s = "hello c file.";

printf ("%sn", unknown);
}


Example Use/Output



$ bash compilewargs.sh cerrfile.c foo bar baz
cerrfile.c: In function ‘int main()’:
cerrfile.c:7:21: error: ‘unknown’ was not declared in this scope
printf ("%sn", unknown);
^
cerrfile.c:5:17: error: unused variable ‘s’ [-Werror=unused-variable]
const char *s = "hello c file.";
^
cc1plus: all warnings being treated as errors

An error occurred, executable not called


What about a file that doesn't exist?



$ bash compilewargs.sh myfile.c foo bar baz
error: file not found 'myfile.c'


What about a text (or any other non-c, cpp or c++) file?



$ bash compilewargs.sh compilewargs.sh foo bar baz
error: first argument not a c/c++ file


By taking the time to think though what the dumbest user you know could ever try and do with your script -- and protecting against it, you can write reasonably robust scripts that will save you grief. Look things over and let me know if you have further questions.






share|improve this answer












You have struggled for a few hours and put something together, but what happens if the compilation fails? What happens if there are no arguments? What happens if there are 4 arguments for the program?



When writing a script, or a program, the most important thing you can do is validate every necessary step! If you are expecting input, validate you received it. Once you have the input, validate it is what your expected. Is it a value within the usable range? Is it a filename that meets my requirements? Does it exist? Did my compile succeed or fail? Do I try and execute the program?



All of these need to be addressed. Otherwise, your script (or program) will stray off on some undefined path.



Bash provides a wealth of conditional expressions that can be used with test (or [...]) or using the bash [[...]] operator. See Bash Manual - 6.4 Bash Conditional Expressions. Make use of the language features to make your code robust.



Bash provides a wealth of string handling features through parameter expansions Bash Manual - 3.5.3 Shell Parameter Expansion, use them to check the extension to make sure it is c, cpp or c++



Putting those features together with a few if...then...fi statements will make your script much more reliable -- and actually do what it is you are trying to do.



The following short script takes arguments (bash Positional Parameters) requiring that at least the filename to compile be provided, and passing any additional arguments to the compiled program as command line arguments with ${@:2} (all bash positional parameters beginning with the 2nd one)



#!/bin/bash

if [ -z "$1" ] ## validate at least one argument given
then
printf "error: insufficient argumentsn" >&2
printf "usage: %s file.cpp [args]n" "${0##*/}" >&2
exit 1
fi

if [ ! -r "$1" ] ## validate file is readable
then
printf "error: file not found '%s'n" "$1" >&2
exit 1
fi

src="$1" ## give source file a handy name

## check the source file ends in '.c', '.cpp' or '.c++'
if [ "${src##*.}" != 'c' -a "${src##*.}" != 'cpp' -a "${src##*.}" != 'c++' ]
then
printf "error: first argument not a c/c++ filen" >&2
exit 1
fi

ext="${src##*.}" ## save the extension

if [ "${#ext}" = 'c' ] ## check if ext is 'c' use gcc else use g++
then
## always enable compiler warnings, -Wall -Wextra -pedantic, minimum
# -Wshadow to catch shadowed variables, -Werror treat warnings as error
gcc -Wall -Wextra -pedantic -Wshadow -Werror
-std=c11 -O3 -o "${src%.*}" "$src"
else
g++ -Wall -Wextra -pedantic -Wshadow -Werror
-std=c++11 -O3 -o "${src%.*}" "$src"
fi

if [ $? -eq '0' ] ## check the compiler return, run only on success
then
./"${src%.*}" ${@:2}
else
printf "nAn error occurred, executable not callednn" >&2
fi


Now a couple of short examples to make sure it works:



#include <stdio.h>

int main (int argc, char **argv) {

const char *s = "hello c file.";

printf ("%sn", s);

for (int i = 1; i < argc; i++)
printf ("arg[%d]: %sn", i, argv[i]);
}


Example Use/Output



$ bash compilewargs.sh cfile.c foo bar baz
hello c file.
arg[1]: foo
arg[2]: bar
arg[3]: baz


For C++



#include <iostream>
#include <string>

int main (int argc, char **argv) {

std::string s = "hello cpp file.";

std::cout << s << 'n';

for (int i = 1; i < argc; i++)
std::cout << "arg[" << i << "]: " << argv[i] << 'n';
}


Example Use/Output



$ bash compilewargs.sh cppfile.cpp foo bar baz
hello cpp file.
arg[1]: foo
arg[2]: bar
arg[3]: baz


Does the error-handling work?



#include <stdio.h>

int main (void) {

const char *s = "hello c file.";

printf ("%sn", unknown);
}


Example Use/Output



$ bash compilewargs.sh cerrfile.c foo bar baz
cerrfile.c: In function ‘int main()’:
cerrfile.c:7:21: error: ‘unknown’ was not declared in this scope
printf ("%sn", unknown);
^
cerrfile.c:5:17: error: unused variable ‘s’ [-Werror=unused-variable]
const char *s = "hello c file.";
^
cc1plus: all warnings being treated as errors

An error occurred, executable not called


What about a file that doesn't exist?



$ bash compilewargs.sh myfile.c foo bar baz
error: file not found 'myfile.c'


What about a text (or any other non-c, cpp or c++) file?



$ bash compilewargs.sh compilewargs.sh foo bar baz
error: first argument not a c/c++ file


By taking the time to think though what the dumbest user you know could ever try and do with your script -- and protecting against it, you can write reasonably robust scripts that will save you grief. Look things over and let me know if you have further questions.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 14 at 8:19









David C. Rankin

39.5k32546




39.5k32546












  • I appreciate your detailed response. I had to turn in the first half of my project tonight, so I put something together that should hopefully work with no problems. I have very little experience when it comes to writing scripts so I was a little lost, but I plan on reading through all the resources provided to me to come up with a better script when the final project is due.
    – random_coder
    Nov 14 at 9:13










  • Just like any language, learn the basics first, and then slowly digest to remaining language features as you go. Be curious. Don't be afraid of man bash (it's a bit cryptic at first, but it is all there). Also, bookmark ShellCheck, Bash Guide, and Bash FAQ and Bash Pitfalls. Bash is an incredible shell - if you can think it -- you can probably do it in bash...
    – David C. Rankin
    Nov 14 at 9:19










  • Thank you for all the information. I can't believe I have not looked into writing bash scripts sooner. They look like fun, and I hope I can free up some time to practice in my spare time.
    – random_coder
    Nov 14 at 9:27


















  • I appreciate your detailed response. I had to turn in the first half of my project tonight, so I put something together that should hopefully work with no problems. I have very little experience when it comes to writing scripts so I was a little lost, but I plan on reading through all the resources provided to me to come up with a better script when the final project is due.
    – random_coder
    Nov 14 at 9:13










  • Just like any language, learn the basics first, and then slowly digest to remaining language features as you go. Be curious. Don't be afraid of man bash (it's a bit cryptic at first, but it is all there). Also, bookmark ShellCheck, Bash Guide, and Bash FAQ and Bash Pitfalls. Bash is an incredible shell - if you can think it -- you can probably do it in bash...
    – David C. Rankin
    Nov 14 at 9:19










  • Thank you for all the information. I can't believe I have not looked into writing bash scripts sooner. They look like fun, and I hope I can free up some time to practice in my spare time.
    – random_coder
    Nov 14 at 9:27
















I appreciate your detailed response. I had to turn in the first half of my project tonight, so I put something together that should hopefully work with no problems. I have very little experience when it comes to writing scripts so I was a little lost, but I plan on reading through all the resources provided to me to come up with a better script when the final project is due.
– random_coder
Nov 14 at 9:13




I appreciate your detailed response. I had to turn in the first half of my project tonight, so I put something together that should hopefully work with no problems. I have very little experience when it comes to writing scripts so I was a little lost, but I plan on reading through all the resources provided to me to come up with a better script when the final project is due.
– random_coder
Nov 14 at 9:13












Just like any language, learn the basics first, and then slowly digest to remaining language features as you go. Be curious. Don't be afraid of man bash (it's a bit cryptic at first, but it is all there). Also, bookmark ShellCheck, Bash Guide, and Bash FAQ and Bash Pitfalls. Bash is an incredible shell - if you can think it -- you can probably do it in bash...
– David C. Rankin
Nov 14 at 9:19




Just like any language, learn the basics first, and then slowly digest to remaining language features as you go. Be curious. Don't be afraid of man bash (it's a bit cryptic at first, but it is all there). Also, bookmark ShellCheck, Bash Guide, and Bash FAQ and Bash Pitfalls. Bash is an incredible shell - if you can think it -- you can probably do it in bash...
– David C. Rankin
Nov 14 at 9:19












Thank you for all the information. I can't believe I have not looked into writing bash scripts sooner. They look like fun, and I hope I can free up some time to practice in my spare time.
– random_coder
Nov 14 at 9:27




Thank you for all the information. I can't believe I have not looked into writing bash scripts sooner. They look like fun, and I hope I can free up some time to practice in my spare time.
– random_coder
Nov 14 at 9:27












up vote
0
down vote













I ended up figuring it out after a while.



#!/bin/bash
echo "Enter TP"
read TP
echo "Enter TC"
read TC
g++ -std=c++11 Project_1.cpp -lpthread -o Project_1
./Project_1 $TP $TC





share|improve this answer

















  • 1




    A read is fine, but your original thought of using command line arguments was much better. You can validate you receive the correct input with if [ -z "$1" -o -z "$2" ]; then printf "error: insufficient inputnusage: %s filename.[c,ccp]n" "${0##*/}"; exit 1; fi If the one argument is not given, the program will then warn and exits displaying the usage: ... information.
    – David C. Rankin
    Nov 14 at 7:22










  • You still need to quote your arguments. Again, feed your scripts to shellcheck.net
    – tripleee
    Nov 14 at 8:35










  • I appreciate all the feedback and I will definitely work on my script. This was my first time putting together a script so I wasn't sure on the best way to approach the problem. On top of this, I had to submit before midnight, so I put something together that should hopefully work with no problems until I can work on a better solution.
    – random_coder
    Nov 14 at 9:10















up vote
0
down vote













I ended up figuring it out after a while.



#!/bin/bash
echo "Enter TP"
read TP
echo "Enter TC"
read TC
g++ -std=c++11 Project_1.cpp -lpthread -o Project_1
./Project_1 $TP $TC





share|improve this answer

















  • 1




    A read is fine, but your original thought of using command line arguments was much better. You can validate you receive the correct input with if [ -z "$1" -o -z "$2" ]; then printf "error: insufficient inputnusage: %s filename.[c,ccp]n" "${0##*/}"; exit 1; fi If the one argument is not given, the program will then warn and exits displaying the usage: ... information.
    – David C. Rankin
    Nov 14 at 7:22










  • You still need to quote your arguments. Again, feed your scripts to shellcheck.net
    – tripleee
    Nov 14 at 8:35










  • I appreciate all the feedback and I will definitely work on my script. This was my first time putting together a script so I wasn't sure on the best way to approach the problem. On top of this, I had to submit before midnight, so I put something together that should hopefully work with no problems until I can work on a better solution.
    – random_coder
    Nov 14 at 9:10













up vote
0
down vote










up vote
0
down vote









I ended up figuring it out after a while.



#!/bin/bash
echo "Enter TP"
read TP
echo "Enter TC"
read TC
g++ -std=c++11 Project_1.cpp -lpthread -o Project_1
./Project_1 $TP $TC





share|improve this answer












I ended up figuring it out after a while.



#!/bin/bash
echo "Enter TP"
read TP
echo "Enter TC"
read TC
g++ -std=c++11 Project_1.cpp -lpthread -o Project_1
./Project_1 $TP $TC






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 14 at 7:13









random_coder

132




132








  • 1




    A read is fine, but your original thought of using command line arguments was much better. You can validate you receive the correct input with if [ -z "$1" -o -z "$2" ]; then printf "error: insufficient inputnusage: %s filename.[c,ccp]n" "${0##*/}"; exit 1; fi If the one argument is not given, the program will then warn and exits displaying the usage: ... information.
    – David C. Rankin
    Nov 14 at 7:22










  • You still need to quote your arguments. Again, feed your scripts to shellcheck.net
    – tripleee
    Nov 14 at 8:35










  • I appreciate all the feedback and I will definitely work on my script. This was my first time putting together a script so I wasn't sure on the best way to approach the problem. On top of this, I had to submit before midnight, so I put something together that should hopefully work with no problems until I can work on a better solution.
    – random_coder
    Nov 14 at 9:10














  • 1




    A read is fine, but your original thought of using command line arguments was much better. You can validate you receive the correct input with if [ -z "$1" -o -z "$2" ]; then printf "error: insufficient inputnusage: %s filename.[c,ccp]n" "${0##*/}"; exit 1; fi If the one argument is not given, the program will then warn and exits displaying the usage: ... information.
    – David C. Rankin
    Nov 14 at 7:22










  • You still need to quote your arguments. Again, feed your scripts to shellcheck.net
    – tripleee
    Nov 14 at 8:35










  • I appreciate all the feedback and I will definitely work on my script. This was my first time putting together a script so I wasn't sure on the best way to approach the problem. On top of this, I had to submit before midnight, so I put something together that should hopefully work with no problems until I can work on a better solution.
    – random_coder
    Nov 14 at 9:10








1




1




A read is fine, but your original thought of using command line arguments was much better. You can validate you receive the correct input with if [ -z "$1" -o -z "$2" ]; then printf "error: insufficient inputnusage: %s filename.[c,ccp]n" "${0##*/}"; exit 1; fi If the one argument is not given, the program will then warn and exits displaying the usage: ... information.
– David C. Rankin
Nov 14 at 7:22




A read is fine, but your original thought of using command line arguments was much better. You can validate you receive the correct input with if [ -z "$1" -o -z "$2" ]; then printf "error: insufficient inputnusage: %s filename.[c,ccp]n" "${0##*/}"; exit 1; fi If the one argument is not given, the program will then warn and exits displaying the usage: ... information.
– David C. Rankin
Nov 14 at 7:22












You still need to quote your arguments. Again, feed your scripts to shellcheck.net
– tripleee
Nov 14 at 8:35




You still need to quote your arguments. Again, feed your scripts to shellcheck.net
– tripleee
Nov 14 at 8:35












I appreciate all the feedback and I will definitely work on my script. This was my first time putting together a script so I wasn't sure on the best way to approach the problem. On top of this, I had to submit before midnight, so I put something together that should hopefully work with no problems until I can work on a better solution.
– random_coder
Nov 14 at 9:10




I appreciate all the feedback and I will definitely work on my script. This was my first time putting together a script so I wasn't sure on the best way to approach the problem. On top of this, I had to submit before midnight, so I put something together that should hopefully work with no problems until I can work on a better solution.
– random_coder
Nov 14 at 9:10



Popular posts from this blog

How to change which sound is reproduced for terminal bell?

Can I use Tabulator js library in my java Spring + Thymeleaf project?

Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents