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.
bash
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.
|
show 4 more comments
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.
bash
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 thePATH
, which is generally considered a very bad idea
– tripleee
Nov 14 at 6:19
For your own convenience you could declare a function likep1 () { ./Project1 "$@"; }
in your interactive shell and then use the shorthandp1
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
|
show 4 more comments
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.
bash
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
bash
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 thePATH
, which is generally considered a very bad idea
– tripleee
Nov 14 at 6:19
For your own convenience you could declare a function likep1 () { ./Project1 "$@"; }
in your interactive shell and then use the shorthandp1
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
|
show 4 more comments
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 thePATH
, which is generally considered a very bad idea
– tripleee
Nov 14 at 6:19
For your own convenience you could declare a function likep1 () { ./Project1 "$@"; }
in your interactive shell and then use the shorthandp1
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
|
show 4 more comments
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.
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 ofman 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
add a comment |
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
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 withif [ -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
add a comment |
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.
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 ofman 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
add a comment |
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.
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 ofman 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
add a comment |
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.
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.
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 ofman 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
add a comment |
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 ofman 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
add a comment |
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
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 withif [ -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
add a comment |
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
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 withif [ -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
add a comment |
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
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
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 withif [ -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
add a comment |
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 withif [ -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
add a comment |
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 shorthandp1
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