I wanted to write the commands as a conditional statement for if i.e., when the command executes without any error it should print success and failure if it fails.
I'm even trying to prevent from printing the long console messages of the commands.
Below is the code that I'm using, which is working perfectly without any conditional statements like printing success or failures messages.
$(BASENAME).pdf: $(BASENAME).ps
ps2pdf $(BASENAME).ps $(BASENAME).pdf
$(BASENAME).ps: $(BASENAME).dvi
dvips -Ppdf $(BASENAME).dvi -o $(BASENAME).ps
I tried changing above as
$(BASENAME).pdf: $(BASENAME).ps
#out=ps2pdf $(BASENAME).ps $(BASENAME).pdf > /dev/null 2>&1 && echo " 5. ps2pdf successful" || echo " 5. ps2pdf failed"
$(BASENAME).ps: $(BASENAME).dvi
dvips -Ppdf $(BASENAME).dvi -o $(BASENAME).ps > /dev/null 2>&1\
if [ $? -eq 0 ];\
then \
echo " 4. dvips successful";\
else \
echo " 4. dvips failed";\
exit 2;\
fi
which is failing my execution and providing me error while running the code like below error
dvips -Ppdf basename_04.dvi -o basename_04.ps \
if [ basename_04.dvi -eq 0 ];\
then \
echo " 4. dvips successful";\
else \
echo " 4. dvips failed";\
exit 2;\
fi
/bin/sh: -c: line 2: syntax error near unexpected token `then'
/bin/sh: -c: line 2: ` then \'
make: *** [basename_04.ps] Error 1
Even after updating with semi-colon, I'm getting below error.
dvips -Ppdf nkukunur_04.dvi -o nkukunur_04.ps > /dev/null 2>&1 ;\
if [ nkukunur_04.dvi -eq 0 ]; \
then \
echo " 4. dvips successful"; \
else \
echo " 4. dvips failed"; \
exit 2; \
fi
/bin/sh: line 1: [: nkukunur_04.dvi: integer expression expected
4. dvips failed
Please help me in fixing the issue.
You are missing a semicolon — and a double-dollar:
$(BASENAME).ps: $(BASENAME).dvi
dvips -Ppdf $(BASENAME).dvi -o $(BASENAME).ps; \
if [ $$? -eq 0 ]; \
then \
echo " 4. dvips successful"; \
else \
echo " 4. dvips failed"; \
exit 2; \
fi
The semicolon missed was the one at the end of the first command line (after $(BASENAME).ps and before the backslash). Assume that make replaces backslash-newline with a blank (not a newline). That's why you need the semicolon after the test; it's why you need one before the if too.
The double-dollar is needed because $? is a Make macro, but you want the shell to see and interpret $?. So, you hide it from Make with $$, which is a macro invocation that expands to $.
So, I don't know what the best practices are for using conditional directives vs using plain Bash conditionals like you are doing. But to fix your code, remove the backslash after the very first line:
dvips -Ppdf $(BASENAME).dvi -o $(BASENAME).ps <<<< removed backslash
if [ $? -eq 0 ];\
then \
echo " 4. dvips successful";\
else \
echo " 4. dvips failed";\
exit 2;\
fi
Otherwise all lines are executed as a single bash statement: the if up until the semicolon are passed as arguments to dvips and then begins a new statement, thus the unexpected token error.
Related
I have below lines in my script and it works fine as of now:
URL="$(hostname -f | grep -q "\.dev\." && echo "$URL_1" || echo "$URL_2")"
FILE="$(hostname -f | grep -q "\.dev\." && echo "file.init.proc" || echo "file.init.test")"
curl --fail -o "$TEMPFILE" "$URL" && if ! grep -q "$TEST_IPD" "$TEMPFILE"; then echo "ipaddress missing in the file" || return 2; else mv -- "$TEMPFILE" "$CONFIG_DIR/$FILE"; rm -f -- "$TEMPFILE"; fi
"line 4- something here"
"line 5- something here"
But earlier there was some problem in my URL and FILE line and because of which my curl line failed and for some reason still line 4 and line 5 got executed and I don't want those lines to be executed.
Let's say for some reason if I am not able to extract URL or FILE variable then if my curl line fails then I don't want line 4 and line 5 to be executed at all. Basically if my curl line fails for whatever reason I don't want line 4 or line 5 to be executed at all.
Let's clean this up a bit.
if hostname -f | grep -qF '.dev.'; then
URL=$URL_1
FILE=file.init.proc
else
URL=$URL_2
FILE=file.init.test
fi
if curl --fail -o "$TEMPFILE" "$URL"; then
if ! grep -q "$TEST_IPD" "$TEMPFILE"; then
echo "ipaddress missing in the file" >&2
return 2
else
mv -- "$TEMPFILE" "$CONFIG_DIR/$FILE" && rm -f -- "$TEMPFILE"
fi
else
"line 4- something here"
"line 5- something here"
fi
--fail just causes curl to exit if something goes wrong; it has no effect on the shell that executed curl. Try to avoid using && and || for anything other than short commands, and never use ... && ... || ... in place of a proper if statement.
There are several ways to stop or continue after a failed command.
Here are some examples:
Include the command as if condition maybe the best way
$ if echo foo; then echo bar; fi
foo
bar
Inspect the exit code to know the result of a given command (the standard is to return a 0 exit code in case of success and a variable code from 1 to 255 in case of error) but as #Charles Duffy said
this is an antipattern because it introduces complexity that wouldn't
exist if you didn't require the exit status to be recorded at all.
More info here
$ echo foo
$ echo $?
0
So you can do something like:
$ echo foo
foo
$ if [[ $? == 0 ]]; then echo bar; fi
bar
Using exit code and arithmetic mode
Testing for success
$ if ! (($?)); then echo bar; fi
bar
Testing for failure
$ if (($?)); then echo bar; fi
Using && ||
$ echo foo && echo bar || echo baz
foo
bar
Speaking about your question, simplify and do something like this:
if curl -o "$TEMPFILE" "$URL"; then
echo SUCCESS
echo "Here's the logic of your 4 and 5 line or whatever you want."
else
echo FAIL
echo "Maybe you should exit with an error code, like this "
exit 1
fi
exit 0
when i build shell script am getting the below error, since am new to CentOS am not able to find out the cause can anyone help me regarding this ??
I guess we need to pass command line parameter while executing am not sure what has to be passed as parameter here.
Shell-script :
#!/bin/sh
# Default place to look for apr source. Can be overridden with
# --with-apr=[directory]
apr_src_dir=../apr
while test $# -gt 0
do
# Normalize
case "$1" in
-*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
*) optarg= ;;
esac
case "$1" in
--with-apr=*)
apr_src_dir=$optarg
;;
esac
shift
done
if test -d "$apr_src_dir"
then
echo ""
echo "Looking for apr source in $apr_src_dir"
else
echo ""
echo "Problem finding apr source in $apr_src_dir."
echo "Use:"
echo " --with-apr=[directory]"
exit 1
fi
# Remove some files, then copy them from apr source tree
rm -f build/apr_common.m4 build/find_apr.m4 build/install.sh \
build/config.guess build/config.sub build/mkdir.sh \
build/make_exports.awk build/make_var_export.awk \
build/get-version.sh
cp $apr_src_dir/build/apr_common.m4 $apr_src_dir/build/find_apr.m4 \
$apr_src_dir/build/install.sh $apr_src_dir/build/config.guess \
$apr_src_dir/build/config.sub $apr_src_dir/build/mkdir.sh \
$apr_src_dir/build/make_exports.awk $apr_src_dir/build/make_var_export.awk \
$apr_src_dir/build/get-version.sh \
build
Error obtained :
[root#localhost apr-iconv]# sh buildconf
buildconf: line 2: $'\r': command not found
buildconf: line 6: $'\r': command not found
buildconf: line 10: syntax error near unexpected token `$'in\r''
'uildconf: line 10: ` case "$1" in
Thank you :)
This error got cleared once shell-script is changed to Unix format. That conversion you can do by executing the command dos2unix <file-name>. If have to install dos2unix to avoid error 'dos2unix: command not found'.
I'm using the following Makefile, which should check whether the files are in some directory *.rpm, if the files hasn't been found i'm going to execute some command (run a script or make the rpm)
Here's a snippet from my Makefile
include /home/user/workspace/test/exec_recipe.mk
export BUILD_LOGS_DIR = $(CURDIR)/build_logs
.PHONY: my_rpm
libpdutil_rpm:
#echo "Making target 'libpdutil_rpm'. Time: $$(date +%T)"
cd /home/user/workspace/test/build/test && $(call exec_recipe,$(ls /home/user/workspace/test/build/test/rpmbuild/RPMS/x86_64d/*.rpm) || $(./test.sh),test.log,)
#echo "Finished making target 'my_rpm'. Time: $$(date +%T)"
And here's the exec_recipe.mk
SHELL:=/bin/bash
exec_recipe = \
echo "The logs dir is: $$BUILD_LOGS_DIR"; \
log_name="$(2)"; \
echo "The log name is $$log_name"; \
cmd="$(1)"; \
eval "$$cmd" 2>&1 | tee -a "$$BUILD_LOGS_DIR/$$log_name"; rc="$${PIPESTATUS[0]}"; \
if [ $$rc = 0 ]; then \
res="PASS"; \
else \
res="FAIL"; \
fi; \
flock $(SUMMARY) echo "Making target '$#': $$res" >> $(SUMMARY); \
exit $$rc
So the problem is when it's reaching the execution of the exec_recipe.mk it giving me some errors:
/bin/bash: eval: line 0: syntax error near unexpected token||'
/bin/bash: eval: line 0: || '
I'm sure that i'm doing something wrong..
I need the helper make file, because i'm using it for other purposes as well
You have to escape all the dollar signs that you don't want make to interpret. You've forgotten to escape the dollar signs in the arguments to $(call exec_recipe,...):
cd /home/user/workspace/test/build/test && $(call exec_recipe,$$(ls /home/user/workspace/test/build/test/rpmbuild/RPMS/x86_64d/*.rpm) || $$(./test.sh),test.log,)
I'm not sure what the final comma is for but whatever.
I have an pages.txt file with 100 URLs inside. I want to check them one by one and fail on the first problem. This is what I'm doing:
cat pages.txt | xargs -n 1 curl --silent \
--output /dev/null --write-out '%{url_effective}: %{http_code}\n'; echo $?
Exit code is 1, but I see it only when the entire file is done. How to stop earlier, on the first problem?
General method
xargs -n 1 sh -c '<your_command> $0 || exit 255' < input
Specific case
xargs -n 1 sh -c 'curl --silent --output /dev/null \
--write-out "%{url_effective}: %{http_code}\n" $0 || exit 255' < pages.txt
Explanation
For every URL in pages.txt, executes sh -c 'curl ... $0 || exit 255' one by one (-n 1) forcing to exit with 255 if the command fails.
From man xargs:
If any invocation of the command exits with a status of 255, xargs will stop immediately without reading any further input. An error message is issued on stderr when this happens.
I haven't found a way to do what you ask for with xargs, but a loop with read might be what you are looking for.
while read URL; do
curl --silent \
--output /dev/null --write-out '%{url_effective}: %{http_code}\n' $URL;
RET=$?;
echo $RET;
if [ $RET -ne 0 ]; then break; fi
done < pages.txt
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