How to understand AS_IF in autoconf? - autoconf

The document says
Macro: AS_IF (test1, [run-if-true1], ..., [run-if-false])
Run shell code test1. If test1 exits with a zero status then run shell code run-if-true1, else examine further tests. If no test exits with a zero status, run shell code run-if-false, with simplifications if either run-if-true1 or run-if-false is empty.
The configure.ac file contains
AS_IF([test "$have_hdf5" != "no"], [AC_DEFINE([HAVE_HDF5], [], [we have HDF5 library + headers])])
But when I type in the run shell code test1, i.e. test "$have_hdf5" != "no", nothing appeared. No matter what I entered (such as test $have_hdf5), I got nothing. But it actually works when I ./configure. So how does the AS_IF and the test1 shell code work? Is it testing some environment variables?

The test utility doesn't have visible output unless you supply an erroneous expression.
test will exit with a 0 status if the expression was true and a nonzero exit status indicates the expression was false (or invalid).
AS_IF tests the exit status of the expression you supply as its first parameter.
If it was 0 (true), the associated block of code is executed. If not, it moves on to the next test expression and performs with the same behavior.
This happens until the macro runs out of tests. Once all tests are found false, it executes the last parameter's contents if the last parameter was supplied.
Edit
Naturally if you don't have "have_hdf5" defined in your current shell, it won't be true when you execute your test expression alone, but if it is true in the configure script, it will do what it is meant to. In any case, output will not happen unless you use an output statement.

The AS_IF M4sh macro will expand out to a portable Bourne shell if statement (when processed by autoconf in the process of writing configure), something like:
if test1 ; then run-if-true1 ... else run-if-false fi
where the interior tests and actions are wrapped in an elif ... ; then ....
Every other parameter starting from the 0th is tested. Usually these are some kind of variable test (e.g. test "$have_hdf5" != "no"), but don't necessarily need to be.

Related

Shell Script: How to read standard output of a program from console

I am trying to write a shell script which gives different inputs to a program and checks the outputs whether they are expected results or not. In conclusion of these tests, I decide whether there is a bug in my executable program.
I run my program over shell script with ./my_program arg1 arg2 (arg1 and arg2 are command line arguments of my program). After that, the script shell constantly gives different inputs to my_program in order to test it and in controlling terminal (or console) standard outputs are iteratively writen like this:
Connection established.
Intermediate result is expected_intermediate_result1
Final result is expected_result1
Connection established.
Intermediate result is expected_intermediate_result2
Final result is expected_result2
And it goes on. For each input, its output is known. So they are matched before.
When connection fails: it is writen Error in connection!
Or result may be wrong:
Connection established.
Intermediate result is result1
Final result is wrong_result1
Apart from giving input, the script has another purpose: check the result.
So I want to read outputs from console and compare them with expected result in order to determine the case in which there is an inconsistency.
I want your assistance to edit this code:
while read console line-by-line
if the line is other than expected result
store this case to text file
done
Some cautions:
I don't want to use expect. I just want to read outputs of the program which is writen in console. I don't use log file so search in a file (grep) will not be used.
Thanks for assistence!
Is this what you're trying to do?
./my_program arg1 arg2 |
grep -Fxq "Final result is expected_result1" || { printf 'Failed: "arg1 arg2" -> "expected_result1"\n'; exit 1; }
If not then edit your question to clarify your requirements and provide a more concrete example.

Tcsh loop while the script returns a specific status

I'm new to Tcsh. I'm trying to write a basic script which runs some other script which returns a status. If it returns 0 then it passed, otherwise it failed. I would like to create a loop which runs the script until it passed and goes to sleep for 30 seconds between every try. I run the script like ./script.pl and I check the status with $?, although I'm not sure it's the right status. The passudo code I though of using is:
set status=`./script.pl`
while($status != 0)
sleep 30
set status=`./script.pl`
end
But I'm not sure it's the right approach.

Equivalent of String.Format in a Chef/Bash Recipe

looking for something similar to .Net string format in a chef recipe ie.
string phone = String.format("phone: {0}",_phone);
I have a Chef recipe where I need to build up a command string with 30 of these params so hoping for a tidy way to build the string, in principle Im doing this
a=node['some_var'].to_s
ruby_block "run command" do
block do
cmd = shell_out!("node mycommand.js #{a}; exit 2;")
end
end
When I try this I get the error
Arguments to path.join must be strings any tips appreciated
Chef runs in two phases:
Compile and Execute (see https://www.chef.io/blog/2013/09/04/demystifying-common-idioms-in-chef-recipes/ for more details).
Your variable assignment to a happens at compile time, e.g. when chef loads all recipes. The ruby block will be execute in execution mode at converge time and cannot access the variable a.
So the easiest solution might be putting the attribute into the ruby block:
ruby_block "run command with argument #{node['some_var']}" do
block do
shell_out!("node mycommand.js #{node['some_var']}")
end
end
However:
If you don't need to execute Ruby code, consider using the execute or bash resource instead.
Keep in mind, that you must have a unique resource name, if you're building some kind of loop around it. An easy way is to put something unique into the name ruby_block "something unique per loop iteration" do ... end
What I really don't understand is your exit code 2. This is an error code. It will make chef throw an exception each time. (shell_out! throws an exception if exit code != 0, see https://github.com/chef/chef/blob/master/lib/chef/mixin/shell_out.rb#L24-L28)
The resource will be executed on each chef run. This is probably not in your interest. Consider adding a guard (test), to prevent unnecessary execution, see https://docs.chef.io/resource_common.html#guards

Handle "race-condition" between 2 cron tasks. What is the best approach?

I have a cron task that runs periodically. This task depends on a condition to be valid in order to complete its processing. In case it matters this condition is just a SELECT for specific records in the database. If the condition is not satisfied (i.e the SELECT does not return the result set expected) then the script exits immediately.
This is bad as the condition would be valid soon enough (don't know how soon but it will be valid due to the run of another script).
So I would like somehow to make the script more robust. I thought of 2 solutions:
Put a while loop and sleep constantly until the condition is
valid. This should work but it has the downside that once the script
is in the loop, it is out of control. So I though to additionally
after waking up to check is a specific file exists. If it does it
"understands" that the user wants to "force" stop it.
Once the script figures out that the condition is not valid yet it
appends a script in crontab and stops. That seconds script
continually polls for the condition and if the condition is valid
then restart the first script to restart its processing. This solution to me it seems to work but I am not sure if it is a good solution. E.g. perhaps programatically modifying the crontab is a bad idea?
Anyway, I thought that perhaps this problem is common and could have a standard solution, much better than the 2 I came up with. Does anyone have a better proposal? Which from my ideas would be best? I am not very experienced with cron tasks so there could be things/problems I could be overseeing.
instead of programmatically appending the crontab, you might want to consider using at to schedule the job to run again at some time in the future. If the script determines that it cannot do its job now, it can simply schedule itself to run again a few minutes (or a few hours, as it may) later by way of an at command.
Following up from our conversation in comments, you can take advantage of conditional execution in a cron entry. Supposing you want to branch based on time of day, you might use the output from date.
For example: this would always invoke the first command, then invoke the second command only if the clock hour is currently 11:
echo 'ScriptA running' ; [ $(date +%H) == 11 ] && echo 'ScriptB running'
More examples!
To check the return value from the first command:
echo 'ScriptA' ; [ $? == 0 ] echo 'ScriptB'
To instead check the STDOUT, you can use as colon as a noop and branch by capturing output with the same $() construct we used with date:
: ; [ $(echo 'ScriptA') == 'ScriptA' ] && echo 'ScriptB'
One downside on the last example: STDOUT from the first command won't be printed to the console. You could capture it to a variable which you echo out, or write it to a file with tee, if that's important.

Collecting return code and stdout string from running SAS program in Linux KornShell script

Some developers and I are using KornShell (ksh) to run SAS programs in a Linux environment. The script invokes a SAS command line and I wish to collect the stdout from the SAS execution (a string defined and written by SAS) as well as the Linux return code (0/1).
My Code (collects stdout into envar, but return_code is always 0 because the envar assignment was successful):
envar=$(./sas XXXX/filename.sas -log $LOG_FILE)
return_code=$?
Is there a way to collect both the return code and the std out without having to submit this command twice?
SAS does not write anything to STDOUT when it is run as a non-interactive process. The log file contains the record of statements executed and step statistics; "printed" output (such as from proc print) is written to a "listing" file. By default, that file will be created using the name of your source file appended with ".lst" (in your case, filename.lst).
You are providing a file to accept the log output using the -log system option. The related option to define the listing file is the -print option. Of course, if the program does not create any listing output, such an option isn't needed.
And as you've discovered, the value returned by $? is the execution return code from SAS. Any non-zero value will indicate some sort of error occurred during program execution.
If you want to influence the return code, you can use the ABORT data step statement in your SAS program. That will immediately halt the SAS program as set the return code to something meaningful to you. For example, suppose you want to terminate further processing if a particular PROC SQL step fails:
data _null_;
rc = symgetn('SQLRC');
put rc=;
if rc > 0 then ABORT RETURN 10;
run;
This would set the return code to 10 and you could use your outer script to send an email to the appropriate person. Such a custom return code value must be greater than 6 and less than 976; other values are reserved for SAS. Here is the SAS doc link.

Resources