How can we evaluate a Mathematica notebook from the command line (i.e. when running the kernel in command line mode)?
Suppose we're working on a remote machine. I know it is possible to convert the notebook to an m-file, and evaluate that, but I'm curious if it's possible to do this directly using the notebook.
This is what I have so far:
First, we need to start a headless X server on the remote Linux machine, so the front end can run there (and open the notebook). Skip this step if you're working on a local machine.
Xvfb :1 &
export DISPLAY=:1
After this I started a Mathematica kernel (math
) and did the following.
It's necessary to use UsingFrontEnd
because opening notebook requires a front end. test.nb has a single input cell containing a=1
.
In[1]:= nb=UsingFrontEnd@NotebookOpen["test.nb"]
Out[1]= -NotebookObject-
After trying to evaluate the notebook, apparently I get a dialog, and I need to use Return[]
to return. I am not sure why the input line starts counting from 1 again (a new kernel was started by the front end?) Note that a
didn't gain a value.
In[2]:= UsingFrontEnd@NotebookEvaluate[nb]
In[1]:= a
Out[1]= a
In[2]:= Return[]
Out[2]= a
After returning from the dialog, a
still doesn't have a value.
In[3]:= a
Out[3]= a
This is a partial answer to your question. The following code opens a notebook, assigns it a
"Test" kernel, evaluates the notebook in that kernel, waits for the evaluation to finish and
saves the evaluated notebook. It does not cause a
to be defined in the local command line kernel though.
This waits for kernel evaluations to finish in the notebook:
NotebookPauseForEvaluation[nb_] := Module[{},
While[ NotebookEvaluatingQ[nb], Pause[.25] ] ]
This checks if any cell in the notebook is still under evaluation:
NotebookEvaluatingQ[nb_]:=Module[{},
SelectionMove[nb,All,Notebook];
Or@@Map["Evaluating"/.#&,Developer`CellInformation[nb]]
]
This is just a diagnostic message, when you're trying to redefine a kernel like "Test":
AddTestEvaluator::exists = "Evaluator `1` is already defined, but has a definition that is `2` and not the expected `3`.";
This is code to add an evaluator, like "Test" to the frontend:
AddTestEvaluator[evaluator_String] := Module[
{evaluatornames, testevaluator},
evaluatornames = EvaluatorNames /. Options[$FrontEnd, EvaluatorNames];
testevaluator = evaluator -> {"AutoStartOnLaunch" -> False};
Which[
MemberQ[evaluatornames, evaluator -> {"AutoStartOnLaunch" -> False}],
Null,
MemberQ[evaluatornames, evaluator -> _],
Message[AddTestEvaluator::exists,
evaluator,
evaluator /. (EvaluatorNames /. Options[$FrontEnd, EvaluatorNames]),
{"AutoStartOnLaunch" -> False}
],
True,
AppendTo[evaluatornames, testevaluator];
SetOptions[$FrontEnd, EvaluatorNames -> evaluatornames]
]
]
Finally, this is the code to evaluate a notebook under a "Test" kernel and save the evaluated kernel:
UsingFrontEnd[
AddTestEvaluator["Test"];
nb = NotebookOpen["test.nb"];
SetOptions[nb,Evaluator->"Test"];
SelectionMove[nb,All,Notebook];
SelectionEvaluate[nb];
NotebookPauseForEvaluation[nb];
NotebookSave[nb]
]
I'm still looking into a solution for your full problem (having a
defined in the local command
line kernel).
This is on Windows, using Arnouds nice work and just adding plain old MathLink (pretty slow btw ...):
link = LinkCreate["8000", LinkProtocol -> "TCPIP"];
UsingFrontEnd[
NotebookPauseForEvaluation[nb_] := Module[{},
While[ NotebookEvaluatingQ[nb], Pause[.25] ] ];
NotebookEvaluatingQ[nb_]:=Module[{},
SelectionMove[nb,All,Notebook];
Or@@Map["Evaluating"/.#&,Developer`CellInformation[nb]]
];
nb = NotebookOpen["G:\\mma\\test.nb"];
SelectionMove[nb, Before, Notebook];
NotebookWrite[nb, Cell["Link = LinkConnect[\"8000\", LinkProtocol -> \"TCPIP\"]", "Input"]];
SelectionMove[nb, After, Notebook];
NotebookWrite[nb, Cell["LinkWrite[Link, a]", "Input"]];
SelectionMove[nb, All, Notebook];
SelectionEvaluate[nb];
a = LinkRead[link];
Print["a = ",a];
]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With