Simple bash script - linux

im new to bash scripting and tring to make a script
goal: reciving 2 names (1 - logfilename 2- program name) the program should compile the program
and send both outputs to a log
if success then write "compile V" and return 0 else compile X and return number
i tried
#!/bin/bash
gcc {$2}.c -Wall -g -o $2> $1 2>&1
exit
and i have no idea how to check if it did or didnt success and the to echo V or X
edit:
thx for you guys, i got this
#!/bin/bash
gcc {$2}.c -Wall -g -o ${2}>${1} 2>&1
if (($?==0));then
echo Compile V
[else
echo compile X]
fi
exit
but all the if parts are still not working...

You can check exit status gcc like this:
#!/bin/bash
# execute gcc command
gcc "$2".c -Wall -g -o "$2"> "$1" 2>&1
# grab exit status of gcc
ret=$?
# write appropriate message as per return status value
((ret == 0)) && echo "compile V" || echo "compile X"
# return the exit status of gcc
exit $ret

You can check the success of a program in bash by command $? if echo $? = 0 then success else fail.

this code should work :
#!/bin/bash
gcc -v ${2}.c -Wall -g -o ${2}>${1} 2>&1
exit

Try this out:
#!/bin/bash
gcc "$2"".c" -Wall -g -o "$2" 2>&1 >"$1"
#check for error of previous command
if $? ; then echo compile V >>"$1"
else echo compile X >>"$1"; fi
exit

Related

Problem when running a shell script after it has been compiled

I have created a shell script which runs perfectly when calling it from command line and giving it each argument. However, when I compile the script using my make file it ignores the case where no arguments are given and prints out nothing.
Is there something wrong with my logic for if no argument was passed in through the command line?
#!/bin/bash
# findName.sh
searchFile="/acct/common/CSCE215-Fall19"
if [[ $1 = "" ]] ; then
echo "ERROR ARGUMENT NEEDED"
exit 2
fi
grep -i $1 ${searchFile}
if [[ $? = "1" ]] ; then
echo "$1 was not found in ${searchFile}"
fi
Edit
#makefile for building
findName: main.o
g++ -g main.o -o findName
# main
main.o: main.cpp
g++ -c -g main.cpp
clean:
/bin/rm -f findName *.o
backup:
tar cvf proj.tar * cpp Makefile *.sh readme
main.cpp
#include <string>
#include <cstdlib>
int main(int argc, char* argv[])
{
std::string command = "./findName.sh";
if(argc == 2)
std::system((command + " " + argv[1]).c_str());
}

Embedding bash script into makefile

I want to include some conditional statement into a makefile:
SHELL=/bin/bash
all:
$(g++ -Wall main.cpp othersrc.cpp -o hello)
#if [[ $? -ne -1 ]]; then \
echo "Compile failed!"; \
exit 1; \
fi
But get an error:
/bin/bash: -c: line 0: conditional binary operator expected /bin/bash:
-c: line 0: syntax error near -1' /bin/bash: -c: line 0:if [[ -ne -1 ]]; then \' makefile:3: recipe for target 'all' failed make: *** [all] Error 1
How to fix it?
Note that each line of a makefile recipe runs in a different shell, so that $? of the previous line is unavailable, unless you use .ONESHELL option.
A fix without .ONESHELL:
all: hello
.PHONY: all
hello: main.cpp othersrc.cpp
g++ -o $# -Wall main.cpp othersrc.cpp && echo "Compile succeeded." || (echo "Compile failed!"; false)
With .ONESHELL:
all: hello
.PHONY: all
SHELL:=/bin/bash
.ONESHELL:
hello:
#echo "g++ -o $# -Wall main.cpp othersrc.cpp"
g++ -o $# -Wall main.cpp othersrc.cpp
if [[ $$? -eq 0 ]]; then
echo "Compile succeded!"
else
echo "Compile failed!"
exit 1
fi
When $ needs to be passed into a shell command it must be quoted as $$ in the makefile (make charges you a dollar for passing one dollar, basically). Hence $$?.

Check return value of g++

I have read this, which suggests the following compilation check:
installCheck () {
if g++ check_opencv.cpp -o check_opencv; then
return 1
else
rm check_opencv
return 0
fi
}
if installCheck $0; then
echo "OpenCV already installed, skipping"
exit 0
fi
However, running this script gives:
check_opencv.cpp:2:33: fatal error: opencv2/core/core.hpp: No such file or directory
compilation terminated.
rm: check_opencv: No such file or directory
OpenCV already installed, skipping
which is wrong. Then I change to this:
installCheck () {
g++ check_opencv.cpp -o check_opencv
if [[ $? -ne 0 ]]; then
and it works fine:
check_opencv.cpp:2:33: fatal error: opencv2/core/core.hpp: No such file or directory
compilation terminated.
Cloning into 'opencv-2.4.9'...
Why is that? Because of some behavior of [[ or g++?
Someone in this says that "Sadly as it turns out make returns 0 weather or not it fails." Shouldn't g++ always return non-zero value when it fails? Maybe I miss something obvious, so please clarify for me. Thank you very much!
Update: it turns out that I understand bash wrongly. A return value of 0 evaluates to true in bash, which is contradictory to what I thought before. This helps.
if g++ check_opencv.cpp -o check_opencv; then
return 1
will return failure (1) if the compilation succeeds. Apparently, you wanted to return failure if the compilation failed, which would be:
if ! g++ check_opencv.cpp -o check_opencv; then
return 1
Or you could just put the true and false branches in the correct order:
installCheck () {
if g++ check_opencv.cpp -o check_opencv; then
rm check_opencv
return 0
else
return 1
fi
}
I don't see anywhere in the linked question where it suggests the code which you proposed.
I suppose that your intention was to avoid contaminating the filesystem if the compilation succeeds, since the compilation itself is the only test needed. You could also achieve this with:
installCheck () {
g++ check_opencv.cpp -o check_opencv
local rv=$?
rm -f check_opencv
return rv
}
if cmd; ... is "true" if cmd is successful i.e. exit status of cmd is 0 - it is logically equivalent to cmd; if [[ $? -eq 0 ]]; ...

How to get exit status of a shell command used in GNU Makefile?

I have a makefile rule in while I am executing a linux tool. I need to check the exit status of the tool command, and if that command fails the make has to be aborted.
I tried checking with $?, $$? \$? etc in the makefile. But they gives me syntax error when makefile runs.
What is the right way to do this ?
Here is the relevant rule in Makefile
mycommand \
if [ $$? -ne 0 ]; \
then \
echo "mycommand failed"; \
false; \
fi
In the makefile-:
mycommand || (echo "mycommand failed $$?"; exit 1)
Each line in the makefile action invokes a new shell - the error must be checked in the action line where the command failed.
If mycommand fails the logic branches to the echo statement then exits.
Here are a couple of other approaches:
shell & .SHELLSTATUS
some_recipe:
#echo $(shell echo 'doing stuff'; exit 123)
#echo 'command exited with $(.SHELLSTATUS)'
#exit $(.SHELLSTATUS)
Output:
$ make some_recipe
doing stuff
command exited with 123
make: *** [Makefile:4: some_recipe] Error 123
It does have the caveat that the shell command output isn't streamed, so you just end up with a dump to stdout when it finishes.
$?
some_recipe:
#echo 'doing stuff'; sh -c 'exit 123';\
EXIT_CODE=$$?;\
echo "command exited with $$EXIT_CODE";\
exit $$EXIT_CODE
Or, a bit easier to read:
.ONESHELL:
some_recipe:
#echo 'doing stuff'; sh -c 'exit 123'
#EXIT_CODE=$$?
#echo "command exited with $$EXIT_CODE"
#exit $$EXIT_CODE
Output:
$ make some_recipe
doing stuff
command exited with 123
make: *** [Makefile:2: some_recipe] Error 123
It's essentially one string of commands, executed in the same shell.
If all you want is for the make to be aborted iff the tool exits with a nonzero status, make will already do that by default.
Example Makefile:
a: b
#echo making $#
b:
#echo making $#
#false
#echo already failed
.
This is what happens with my make:
$ make
making b
make: *** [Makefile:6: b] Error 1
Make sure partially or wholly created targets are removed in case you fail.
For instance, this
a: b
#gena $+ > $#
b:
#genb > $#
is incorrect: if on the first try, genb fails, it will probably leave an incorrect b, which, on the second try, make will assume is correct. So you need to do something like
a: b
#gena $+ > $# || { rm $#; exit 1; }
b:
#genb > $#
To those who can't still fix it, the original snippet in the question missed a semicolon after mycommand. So, the working example is:
mycommand; \ # <<== here's the missing semicolon
if [ $$? -ne 0 ]; \
then \
echo "mycommand failed"; \
false; \
fi

Wrapping GNU makefile with another makefile

This is following question.
I have Makefile.real (Makefile from prev question):
all: a b
a:
echo a
exit 1
b:
echo b start
sleep 1
echo b end
Now I want to create Makefile that is simple wrap of Makefile.real:
It calls make with Makefile.real with the same args as it was called
It should print error message id Makefile.real fails
This is my goal - print error message in the end of parallel make
(see question)
Therefore following commands should terminate with error message:
make -j1 a b (1)
make -j2 a b (2)
I suspect Makefile should be something close to:
%:
$(MAKE) -f Makefile.real $(MAKECMDGOALS); \
res=$$?; if [ $$res != 0 ]; then echo "Failed!!!"; fi; exit $$res
The problem is that target '%' will be called twice for a and b for (2).
Any ideas?
This is the solution I ended with
ifneq ($(REAL_MAKE),1)
# run_make will be called once (it's .PHONY target),
# even if make is called with several targets
%: run_make
#:
.PHONY: run_make
run_make:
$(MAKE) $(MAKECMDGOALS) REAL_MAKE=1; \
if [ $$? -ne 0 ]; then \
echo "*** Error ***" >&2; \
exit 1; \
fi
else # REAL_MAKE defined (actual makefile)
### HERE comes original make we want to wrap ###
endif # # REAL_MAKE defined (actual makefile)

Resources