How to call one macro program from another in SAS Enterprise Guide? - sas

Is there any macro command that allows calling one program from another (the %run_program() pseudo code)?
Program "Settings":
%let myvar="HELLO WORLD!";
Program "Program":
%run_program(Settings); *Pseudo-code;
%put &myvar; *Should print *Should print "HELLO WORLD!";

This is not exact answer on your question, but if you only want to be sure that Settings is run before Program when Run Process Flow you can link them together.
Right click Settings,
choose Link Settings to...,
and pick Program from the dialog.
Run Process FLow And see the Hello World be printed in the log.

I think that you are looking for the %include function.
You would have to save 'Settings' as a stand-alone program on your server like '/myserver/somefolder/settings.sas'.
Then you could ensure that it is run via:
...some code
%include ('/myserver/somefolder/settings.sas');
... more code
The program would run exactly as it would if you copy-pasted the contents of 'settings.sas' into the current program.

In addition to the Process Flow, you also can create an Ordered List. This allows you to run programs in a single process flow in multiple different orders (or run a subset of a process flow).
You create that in New -> Ordered List, then Add programs to it, move them up/down in the order you want. Then you see the ordered list on the left in the project tree and can right click to run it (or select then F8).
There is not a macro command to run a program in enterprise guide; you can use automation via .NET if you want to do things like that. Chris Hemedinger on The SAS Dummy has a good article on EG automation.

Related

automatic debugging with gdb

I am dealing with a large code base with tons of globals. Under some peculiar set of data it produces the wrong result. I wanted to automatically run few scenarios with gdb in automatic step-by-step execution and periodical dumping
of some values and recording the tracing in some file. Doing it manually will ruin my sight and my brain. I speculate that there is some globals mess-up. How to do this automatically? Use some scripting. All this is in RH linux.
Thanks in advance.
tried to do this manually using conditional breaks, but gave up after a while
I wanted to automatically run few scenarios with gdb in automatic step-by-step execution and periodical dumping of some values and recording the tracing in some file.
It may be significantly more effective to run the program under reverse debugger (such as rr), and trace the wrong result back to its source.
How to do this automatically?
You can't do automatically what you can't express as an algorithm, and you haven't described an algorithm you want to use. If it's something like "stop every 100 times foo is called and print the values of these 500 globals", than that's trivially automatable with GDB.
More complicated algorithms are possible with the use of embedded Python.
In the .gdbinit file in your home folder add
add-auto-load-safe-path /path_to_the_folder_containing_your_executable/
Now you can create another .gdbinit file in the same folder where your executable is that will be loaded when you start gdb from there (the .gdbinit file in your home that is also read - useful if you have nice stuff there such as loading pretty printers).
In this .gdbinit file, add the code below
file your_executable_name
start
# Optional
set args "<any command line parameters you program might need>"
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Add gdb commands below to set breakpoints, print variable values, etc
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
run
Gdb is very powerful and I'll list a few things that might help this automation.
You can set breakpoints with b filename.ext:line_number or b function_name
You can use commands breakpoint_number (see here) and then list commands that should be run after this breakpoint is hit. Use end to finish the commands
You know the breakpoint number, since they are created sequencially (note that the start will count as a breakpoint and thus the first one you add will be breakpoint 2)
You can use convenience variables to store useful things such as the address of an important object
The python api is very powerful
One idea is that you can save the address of the important global variables (if they are not always accessible) using convenience variables. For instance, add a breakpoint where this global variable is and then add to this breakpoint the command to save the address of this variable to a convenience variable followed by continue (with continue you will not see gdb stopping there).
set $var1 = &myglobal
continue
You might want to also delete this breakpoint with delete breakpoint_number before continue to avoid stopping at this breakpoint again.
Then as long is the object exists you can inspect it using p $var1 or p $var1->something when the program is stopped at a different breakpoint where myglobal might not be directly accessible.
In the commands that you add to be run when a breakpoint is hit you can do things such as echo message explaining where you are, p some_var to see the values of variables or even python some_complicated_python_code.
In the case you want to use python for more power it is worth reading the section about it in the manual. Let-me give you one example. Suppose one of your global variables was stored in a convenience variable called "$myvar". Then you can pass it to the python interpreter with
python myvar = gdb.parse_and_eval("$myvar")
You can also pass any variable in the current scope to parse_and_eval.
Now, suppose this global variable stores an object of a class with a "n_elem" attribute you want to check. You can print it with
python print(myvar["n_elem"])
You can also create a python file in the same folder and use
python from my_python_file import *
to import functions defined there.
With these gdb features you can pretty much automate whatever you might need.

Start .exe file and automatically "press enter for "Save"" in SAS

I have a SAS program I would like to schedule, so we don't have to run it manually.
In the program we call an excecutable (reg.exe), like this:
X CALL "K:\reg.exe";
The executable opens a standard windows save-dialog and all we need to do is press save, which will save an xml-file. The save-dialog already opens in the correct directory.
What I would like is to somehow pass the instruction on, using code, to "press save", so the program can move on and work with the saved xml-file.
Is this possible somehow?
Thanks for your help!
Thomas:
There are numerous Windows utilities for scripted control of an interactive program. For example: AutoIt (my favorite), MouseRobot and AutoHotKey to name a few.
The statement
options xmin noxwait noxsync;
will cause the external program to run, not wait for the command session to exit, and not wait for the command to complete.
If your SAS programs needs to wait for the side effects of the scripting use of reg.exe to occur before occurring, use:
options xmin noxwait xsync;
These settings affect other operating system interfacing features, such as:
X command
CALL SYSTEM routine
%SYSEXEC statement
The use of your reg.exe might require your login to have admin rights.
The SYSTASK statement can also run external commands.
If you find that you are unable to run external commands, it is probably because the system setting NOXCMD is active. This setting is on by default in SAS server environments.

Terminate whole process flow instead of single program

Is there a way to stop the process if certain criteria in any of the programs in this process is met?
I have a process consist of 5 SAS programs. This process is scheduled to run at 8am every morning. However, sometimes the database is not refreshed and this process will send out weird figures.
I need to have "exception control".. In 2nd program I check the database with some criteria. If no error, then keep running the rest of the code. Otherwise, send out an notification email and STOP running the 2nd program and all the subsequent programs.
I try %abort cancel but it only terminate the current program. The subsequent programs are not affected.. I can do checking in every single program but that make the code redundant...
I also try google "terminate SAS process" but most of them refer to abort statements which doesn't help...
If you're using Enterprise Guide, this is built into the program via logic gates.
First, in the program that determines whether the database file passed/failed ("gate program"), assign a macro variable a value based on that test. Presumably this program will do only things you're happy for it to do even if it fails.
On the process flow page, you right click on the program that determines if the database file passed/failed, and select 'Condition -> Add'.
Then add a condition based on a Macro Variable, and use 'equals' and the value you're looking for (or 'greater than' or whatever makes sense). Then select the next task after "Then run this task"; and put the other option after Else run this task.
Then, whichever of the two is forward-moving, should then have links to the rest of the programs you want run; the one that's not should end the process.
SAS gives an example of how to do that in KB Sample 39995 including a sample project you can download.
Second, you can set OBS=0 if you reach the error condition. This will let SAS continue working, but it in most cases won't be able to do anything (since OBS=0, then it can only affect 0 records of any dataset). I'm not sure that's a guarantee that it won't do anything, but in everything I've done that's been sufficient. I also have used OPTIONS ERRORABEND which works fine if you do all of your processing with external libnames which won't automatically reconnect when SAS is reconnected.
My understanding is that this is a batch process. You don't specify Operating System you are running your process on. Let's suppose you are running it on UNIX/Linux (I am hoping it is similar on Windows). Let's assume that your 5-programm process is run by the following shell script:
sas /program1.sas
sas /program2.sas
sas /program3.sas
sas /program4.sas
sas /program5.sas
If you want to stop your remaining process after program2.sas completes with ERRORs or WARNINGs you can modify your script to be
sas /program1.sas
sas /program2.sas
if [ $? -ne 0 ]
then
exit
fi
sas /program3.sas
sas /program4.sas
sas /program5.sas
In this script code a special shell script variable $? status code is passed from the previous command from SAS (0 means successful completion). If it is not 0 then the whole script stops due to the exit command.
For more information and code examples see How to conditionally terminate a SAS batch flow process in UNIX/Linux SAS blog post.

Completely stop Enterprise guide on condition

So, I have a simple project with one Program (user-writen code) and then one Add-Inn (custom task) (it is very useful System Command executor add-inn, about you can read here)
So, when I get some condition in Program step, I want to stop my Project. I could stop Program, for example, using
ENDSAS
or
Abort abend
but, even if Program immediately stops (with error message in log), Add-Inn is execute! How disable executing of Add-Inn on condition (on error or any other)?
Thanks
P.S. Project will be execute in batch mode
If you're using an EG process flow, as you presumably are, then you need to set up a condition to run the add-in task.
Right click on your one program, select 'condition', add. Let's say you have a macro variable that is set to 0 if you have no problems or (some value) if you have a problem. (Could also use any of the automatic SYSERR type macro variables.)
Then, put your add-in task under "Then, run this task". You can add an Else or Else If if you want, or just leave that as None.
Then, EG won't run your task unless the macro variable is successful.

Auto Scheduled SAS Queries

I run some SAS queries monthly and they all take a fairly long time to run. I was wondering if there was any way I can schedule these to run on a certain date each month in a certain order?
Thanks for your help!
On unix you could set the programs up to run in batch mode with a cron job.
One trick you could use would be to set up a master SAS program to run everything.
Make one program that just contains any global variables that need to be changed each month and then call your monthly programs with includes.
something like:
%let globalvar1 = ThisMonth;
%let globalvar2 = LastMonth;
%include '/path/to/sas/program1';
%include '/path/to/sas/program2';
Then you run only this one program in batch...it will run them in the correct order and automatically wait for them to finish executing before moving to the next program (setting up separate cron jobs would require you to overestimate how long each one takes so they wouldn't conflict).
This will dump everything into one log file...which may be good or bad.
Another option would be to use X to call the program from the OS at each run.
I am not 100% on the syntax but this should work if you use the right syntax for your OS (this could work on unix or windows so you would only have to schedule one program).
At the end of each program just add:
X "Path/to/sas.exe" -batch -noterminal nextProgram.sas
This will let you chain the programs together so that they start the next one running after they finish. Then you just use task scheduler/cron to start "sas.exe -batch -noterminal firstProgram.sas"
Depending on what system you are working with, methods may be different.
The main idea is that you may store all queries to a SAS processing file then use system's scheduler (For example, task scheduler for Windows), to run monthly.
A quick help (for Windows):
http://analytics.ncsu.edu/sesug/2006/CC04_06.PDF