Scripting
In the console section of the users guide, we introduced the scripting support.
Assignation
You already know the first usage of scripting: execution of command.
karaf@root()> echo hello world hello world
You can also assign a value to session variables:
karaf@root()> msg = "hello world" hello world
Once you have assigned a value to a variable, you can display this value using the "resolved" variable name:
karaf@root()> echo $msg hello world
The () are execution quotes (like the backquotes when you use bash on Unix).
karaf@root()> ($.context bundle 1) location mvn:org.apache.karaf.jaas/org.apache.karaf.jaas.modules/4.0.0
The $.context
access the context variables in the current session.
We access to the bundle
variable (an array containing all bundles), and we want to display the bundle location for
the bundle at the index 1 in the bundle array.
Expressions
The shell has a built-in expression parser. Expressions must be enclosed with the %(…)
syntax.
Examples:
karaf@root()> %(1+2) 3 karaf@root()> a = 0 0 karaf@root()> %(a+=1) 1 karaf@root()> %(a+=1) 2 karaf@root()> b=1 1 karaf@root()> %(SQRT(a^2 + b^2)) 1.7320508
Mathematical Operators
Operator | Description |
---|---|
+ |
Additive operator |
- |
Subtraction operator |
* |
Multiplication operator |
/ |
Division operator |
% |
Remainder operator (Modulo) |
^ |
Power operator |
Boolean Operators
Operator | Description |
---|---|
= |
Equals |
== |
Equals |
!= |
Not equals |
<> |
Not equals |
< |
Less than |
⇐ |
Less than or equal to |
> |
Greater than |
>= |
Greater than or equal to |
&& |
Boolean and |
|| |
Boolean or |
Supported Functions
Function | Description |
---|---|
NOT(expression) |
Boolean negation, 1 (means true) if the expression is not zero |
IF(condition,value_if_true,value_if_false) |
Returns one value if the condition evaluates to true or the other if it evaluates to false |
RANDOM() |
Produces a random number between 0 and 1 |
MIN(e1,e2) |
Returns the smaller of both expressions |
MAX(e1,e2) |
Returns the bigger of both expressions |
ABS(expression) |
Returns the absolute (non-negative) value of the expression |
ROUND(expression,precision) |
Rounds a value to a certain number of digits, uses the current rounding mode |
FLOOR(expression) |
Rounds the value down to the nearest integer |
CEILING(expression) |
Rounds the value up to the nearest integer |
LOG(expression) |
Returns the natural logarithm (base e) of an expression |
SQRT(expression) |
Returns the square root of an expression |
SIN(expression) |
Returns the trigonometric sine of an angle (in degrees) |
COS(expression) |
Returns the trigonometric cosine of an angle (in degrees) |
TAN(expression) |
Returns the trigonometric tangens of an angle (in degrees) |
SINH(expression) |
Returns the hyperbolic sine of a value |
COSH(expression) |
Returns the hyperbolic cosine of a value |
TANH(expression) |
Returns the hyperbolic tangens of a value |
RAD(expression) |
Converts an angle measured in degrees to an approximately equivalent angle measured in radians |
DEG(expression) |
Converts an angle measured in radians to an approximately equivalent angle measured in degrees |
Functions names are case insensitive.
Supported Constants
Constant | Description |
---|---|
PI |
The value of PI, exact to 100 digits |
TRUE |
The value one |
FALSE |
The value zero |
List, maps, pipes and closures
Using [], you can define an array variable:
karaf@root()> list = [1 2 a b] 1 2 a b
You can also create a map if you put variables assignation in the array:
karaf@root()> map = [Jan=1 Feb=2 Mar=3] Jan 1 Feb 2 Mar 3
Using the | character, you can pipe output from a command as an input to another one.
For instance, you can access to the bundles context variables and send it as input to the grep command:
karaf@root()> ($.context bundles) | grep -i felix 0|Active | 0|org.apache.felix.framework (4.2.1) 21|Active | 11|org.apache.felix.fileinstall (3.2.6) 43|Active | 10|org.apache.felix.configadmin (1.6.0) 51|Active | 30|org.apache.felix.gogo.runtime (0.10.0)
You can assign a name to a script execution. It’s what we use for alias:
karaf@root()> echo2 = { echo xxx $args yyy } echo xxx $args yyy karaf@root()> echo2 hello world xxx hello world yyy
Startup
The etc/shell.init.script
file is executed at startup in each shell session, allowing the definition of additional
variables or aliases or even complex functions. It’s like the bashrc or profile on Unix.
Constants and variables
Apache Karaf console provides a set of implicit constants and variables that you can use in your script.
-
$.context
to access a bundle context -
$.variables
to access the list of defined variables -
$.commands
to access the list of defined commands
The variables starting with a # that are defined as Function (such as closures) will be executed automatically:
karaf@root> \#inc = { var = "${var}i" ; $var } var = "${var}i" ; $var karaf@root> echo $inc i karaf@root> echo $inc ii karaf@root>
Built-in variables and commands
Apache Karaf console provides built-in variables that are very useful for scripting:
-
$args
retrieves the list of script parameters, given to the closure being executed -
$1 .. $999
retrieves the nth argument of the closure -
$it
(same as$1
) is used in a loop to access the current iterator value
Apache Karaf console provides commands for scripting:
-
shell:if
-
shell:new
-
shell:each
-
…
See the full list of shell
commands for details.
Leveraging existing Java capabilities (via reflection)
Apache Karaf console supports loading and execution of Java classes.
The $karaf.lastException
implicit variable contains the latest Exception thrown.
karaf@root()> ($.context bundle) loadClass foo Error executing command: foo not found by org.apache.karaf.shell.console [17] karaf@root()> $karaf.lastException printStackTrace java.lang.ClassNotFoundException: foo not found by org.apache.karaf.shell.console [17] at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1460) at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72) at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843) at java.lang.ClassLoader.loadClass(ClassLoader.java:247) at org.apache.felix.framework.Felix.loadBundleClass(Felix.java:1723) at org.apache.felix.framework.BundleImpl.loadClass(BundleImpl.java:926) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.felix.gogo.runtime.Reflective.invoke(Reflective.java:137) at org.apache.felix.gogo.runtime.Closure.executeMethod(Closure.java:527) at org.apache.felix.gogo.runtime.Closure.executeStatement(Closure.java:403) at org.apache.felix.gogo.runtime.Pipe.run(Pipe.java:108) at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:183) at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:120) at org.apache.felix.gogo.runtime.CommandSessionImpl.execute(CommandSessionImpl.java:89) at org.apache.karaf.shell.console.jline.Console.run(Console.java:166) at java.lang.Thread.run(Thread.java:680)
It’s possible to create objects to create commands "on the fly":
karaf@root()> addcommand system (($.context bundle) loadClass java.lang.System) karaf@root()> system:getproperty karaf.name root
It means that you can create an object using the new
directive, and call methods on the objects:
karaf@root> map = (new java.util.HashMap) karaf@root> $map put 0 0 karaf@root> $map 0 0
Examples
The following examples show some scripts defined in etc/shell.init.script
.
The first example shows a script to add a value into a configuration list:
# # Add a value at the end of a property in the given OSGi configuration # # For example: # > config-add-to-list org.ops4j.pax.url.mvn org.ops4j.pax.url.mvn.repositories http://scala-tools.org/repo-releases # config-add-to-list = { config:edit $1 ; a = (config:property-list | grep --color never $2 | tac) ; b = (echo $a | grep --color never "\b$3\b" | tac) ; if { ($b trim) isEmpty } { if { $a isEmpty } { config:property-set $2 $3 } { config:property-append $2 ", $3" } ; config:update } { config:cancel } }
This second example shows a script to wait for an OSGi service, up to a given timeout, and combine this script in other scripts:
# # Wait for the given OSGi service to be available # wait-for-service-timeout = { _filter = $.context createFilter $1 ; _tracker = shell:new org.osgi.util.tracker.ServiceTracker $.context $_filter null ; $_tracker open ; _service = $_tracker waitForService $2 ; $_tracker close } # # Wait for the given OSGi service to be available with a timeout of 10 seconds # wait-for-service = { wait-for-service-timeout $1 10000 } # # Wait for the given command to be available with a timeout of 10 seconds # For example: # > wait-for-command dev watch # wait-for-command = { wait-for-service "(&(objectClass=org.apache.felix.service.command.Function)(osgi.command.scope=$1)(osgi.command.function=$2))" }