执行脚本
在调用者脚本的操作范围内同步运行脚本。
命令可用性: 本地 IBM RPA SaaS 和 IBM RPA
描述
执行脚本 (executeScript) 命令在调用 执行脚本的脚本操作期间装入脚本并同步运行其命令。 作为参考,使用 执行脚本 命令的脚本称为调用者脚本,而在 "执行脚本" 命令中引用的脚本称为引用脚本。
您可以使用 执行脚本 从 IBM RPA 服务器的租户装入本地脚本或脚本。 如果您至少满足下列其中一个必要条件,那么机器人运行时将高速缓存引用的脚本以供后续使用:
- 您正在引用本地脚本。
- 您正在从租户引用特定版本的脚本。
如果您不满足任何先前的必要条件,那么 Bot Runtime 每次调用 执行脚本时都会下载引用的脚本。
如果引用的脚本具有输入参数,那么可以将初始值发送到这些参数,这意味着这些参数或变量将保留您发送给它们的值,而不是在引用的脚本启动时保留它们的缺省值。
如果引用的脚本具有输出参数,那么在引用的脚本结束时,可以通过将这些参数与调用者脚本的变量绑定来将其值装入调用者脚本。
在调用者脚本的操作期间,引用的脚本将同步运行。 这意味着当 执行脚本 运行时,当调用者脚本等待此操作结束时,来自所引用脚本的命令将逐个运行。 如果引用的脚本失败,那么可以通过启用 Handle error (handleError) 参数来忽略 "执行脚本" 命令中的错误,或者使用 Handle Error (onError) 命令捕获错误事件。
如果启用 处理错误 参数,并且 执行脚本 调用的脚本失败,那么运行 执行脚本 的脚本中的 error 环境变量将包含来自失败脚本的错误元数据。 有关 error 环境变量存储的元数据的详细信息,请参阅 error 环境变量 。
脚本语法
IBM RPA 的专有脚本语言的语法与其他编程语言类似。 该脚本语法在脚本文件中定义命令的语法。 您可以在 IBM RPA Studio的 脚本 方式下使用此语法。
executeScript [--handleError(Boolean)] [--isfromfile(Boolean)] --filename(String) --name(String) [--parameters(String)] [--output(String)] [--version(Numeric)] (Boolean)=value (String)=errormessage (Numeric)=linenumber (String)=errorsubname (Error)=error
输入参数
下表显示了此命令中提供的输入参数的列表。 在表中,您可以看到在 IBM RPA Studio的脚本方式及其 Designer 方式等效标签中工作时的参数名称。
| 设计器方式标签 | 脚本方式名称 | 必需的 | 接受的变量类型 | 描述 |
|---|---|---|---|---|
| 处理错误 | handleError |
Optional |
Boolean |
如果启用 处理错误 参数,并且 执行脚本 调用的脚本失败,那么运行 执行脚本 的脚本中的 error 环境变量将包含来自失败脚本的错误元数据。 有关 error 环境变量存储的元数据的详细信息,请参阅 error 环境变量 。 |
| 文件 | isfromfile |
Optional |
Boolean |
如果已启用,那么必须通过提供其 Filename 参数的绝对文件路径来引用本地脚本。 如果禁用,那么必须在 名称 参数中引用来自 IBM RPA Control Center 租户的脚本。 此参数 不推荐。 请改为使用 Name 参数。 |
| 文件名 | filename |
Required when the File parameter is True |
Text |
要运行的脚本的绝对文件路径。 此参数 不推荐。 此参数中的数据将自动迁移到 Name 输入参数。 |
| 名称 | name |
Required when the File parameter is False |
Text |
要运行的租户中脚本的名称。 它接受脚本的绝对文件路径或仅接受要运行的脚本的名称。 如果仅指定了名称,那么该脚本必须已发布到您登录的同一租户。 |
| 参数 | parameters |
Optional |
Text |
将引用的脚本中的输入参数绑定到调用者脚本中的值或变量,在引用的脚本开始其操作时将调用者脚本中的值装入到引用的脚本的输入参数。parameter 字段引用引用的脚本中的输入参数变量。value 字段必须是要发送到其相关输入参数的值或来自调用者脚本的变量。 如果使用变量,那么此变量中存储的值将发送到所引用脚本的输入参数。 |
| 输出 | output |
Optional |
Text |
将所引用脚本中的输出参数与调用者脚本中的变量绑定,当所引用脚本结束其操作时,将输出参数中的值装入调用者脚本的变量。parameter 字段引用所引用脚本中的输出参数变量。value 字段引用调用者脚本中的变量。 |
| 版本 | version |
Optional |
Number |
要运行的脚本的版本。 留空以引用生产版本。 仅当禁用了 file 时,才能设置 version 。如果设置 version,那么 Bot Runtime 会高速缓存脚本以提高性能。 否则, Bot Runtime 会在每次运行时下载该脚本。 |
输出参数
| 设计器方式标签 | 脚本方式名称 | 接受的变量类型 | 描述 |
|---|---|---|---|
| 成功 | value |
Boolean |
返回所引用脚本的操作的状态。 True 如果成功; False 如果操作失败。仅当您启用 处理错误时,才能使用此参数。 如果脚本失败,那么它将返回 True。 检查在 错误消息, 错误行号, 错误例程名称 和 错误 输出参数中获取的变量,以确定在执行所调用脚本期间发生的问题。 |
| 错误消息 | errormessage |
Text |
返回引用的脚本在失败时产生的错误消息。 仅当您启用 处理错误时才能使用此参数。 |
| 错误行号 | linenumber |
Number |
返回在引用的脚本失败时发生错误的行号。 仅当您启用 句柄错误时才能使用此参数。 |
| 错误例程名称 | errorsubname |
Text |
返回在引用的脚本失败时发生错误的子例程名称。 仅当您启用 处理错误时才能使用此参数。 |
| 错误 | error |
Error |
如果引用的脚本失败,那么返回错误事件的完整详细信息。 仅当您启用 处理错误时,才能使用此参数。 |
示例
示例 1
假设您拥有一家咖啡店,并且希望跟踪客户和商品的订单。 数据库必须具有四个表:
- 客户机: 此表存储有关客户机的信息,例如其名称和电子邮件地址。
- 订单: 此表存储有关订单的信息,例如订单标识和客户标识。
- 产品: 此表存储有关产品的信息,例如产品标识,产品名称和价格。
- 订单商品: 此表存储有关每个订单商品的信息,例如订单标识和产品标识。
将为您提供任务,以获取客户在您的店铺中花费的最高金额的名称和总购买金额。
要创建,填充和查询此数据库,您可以根据需要将脚本的逻辑分隔成不同的文件,并使用 执行脚本 命令从主脚本调用每个脚本。
要运行此示例,请创建四个单独的 WAL 脚本文件,并将其放在桌面中:
connectToDb.wal:
defVar --name databasePath --type String --parameter --required
defVar --name sqliteConnection --type DbConnection --output
defVar --name connectionSuccess --type Boolean
defVar --name pathExists --type Boolean
defVar --name path --type String
ifFile --file "${databasePath}" pathExists=value
if --left "${pathExists}" --operator "Is_True"
sqliteConnect --connectionString "Data Source=\"${databasePath}\";Version=3;UseUTF16Encoding=True;" sqliteConnection=connection
else
sqliteConnect --createNew --path "${databasePath}" sqliteConnection=connection connectionSuccess=success
sqlExecute --connection ${sqliteConnection} --statement "CREATE TABLE IF NOT EXISTS clients (client_id INTEGER PRIMARY KEY AUTOINCREMENT,first_name TEXT NOT NULL,last_name TEXT NOT NULL,email TEXT NOT NULL);"
sqlExecute --connection ${sqliteConnection} --statement "CREATE TABLE IF NOT EXISTS products (product_id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT NOT NULL,price REAL NOT NULL);"
sqlExecute --connection ${sqliteConnection} --statement "CREATE TABLE IF NOT EXISTS orders (order_id INTEGER PRIMARY KEY AUTOINCREMENT,client_id INTEGER,FOREIGN KEY(client_id) REFERENCES clients(client_id));"
sqlExecute --connection ${sqliteConnection} --statement "CREATE TABLE IF NOT EXISTS order_items (order_item_id INTEGER PRIMARY KEY AUTOINCREMENT,order_id INTEGER,product_id INTEGER NOT NULL,quantity INTEGER NOT NULL,FOREIGN KEY(order_id) REFERENCES orders(order_id),FOREIGN KEY(product_id) REFERENCES products(product_id));"
endIf
checkDb.wal:
defVar --name databaseConnection --type DbConnection --parameter --required
defVar --name result --type Numeric --output
sqlExecuteScalar --connection ${databaseConnection} --statement "SELECT COUNT(*) FROM orders;" result=value
insertData.wal:
defVar --name databaseConnection --type DbConnection --parameter --required
sqlExecute --connection ${databaseConnection} --statement "INSERT INTO clients (first_name, last_name, email)\r\nVALUES\r\n(\'John\', \'Doe\', \'john.doe@example.com\'),\r\n(\'Jane\', \'Doe\', \'jane.doe@example.com\'),\r\n(\'Peter\', \'Parker\', \'peter.parker@example.com\'),\r\n(\'Bruce\', \'Wayne\', \'bruce.wayne@example.com\'),\r\n(\'Clark\', \'Kent\', \'clark.kent@example.com\');"
sqlExecute --connection ${databaseConnection} --statement "INSERT INTO products (name, price)\r\nVALUES\r\n(\'Espresso\', 3.99),\r\n(\'Latte\', 4.99),\r\n(\'Capuccino\', 5.99),\r\n(\'Macchiato\', 4.50),\r\n(\'Americano\', 3.50),\r\n(\'Iced coffee\', 4.50),\r\n(\'Cold brew coffee\', 5.00),\r\n(\'Frappuccino\', 6.00),\r\n(\'Mocha\', 5.50),\r\n(\'White chocolate mocha\', 6.00);"
sqlExecute --connection ${databaseConnection} --statement "INSERT INTO orders (client_id)\r\nVALUES\r\n(1),\r\n(2),\r\n(3),\r\n(4),\r\n(5);"
sqlExecute --connection ${databaseConnection} --statement "INSERT INTO order_items (order_id, product_id, quantity)\r\nVALUES\r\n(1, 1, 2),\r\n(1, 2, 1),\r\n(2, 3, 3),\r\n(2, 4, 1),\r\n(3, 5, 2),\r\n(3, 6, 1),\r\n(4, 7, 3),\r\n(4, 8, 1),\r\n(5, 9, 2),\r\n(5, 10, 1);"
queryDb.wal:
defVar --name databaseConnection --type DbConnection --parameter --required
defVar --name dataTable --type DataTable --output
sqlExecuteReader --connection ${databaseConnection} --statement "SELECT first_name, last_name, SUM(quantity * products.price) AS total_spent\r\nFROM clients\r\nJOIN orders ON clients.client_id = orders.client_id\r\nJOIN order_items ON orders.order_id = order_items.order_id\r\nJOIN products ON order_items.product_id = products.product_id\r\nWHERE products.price IS NOT NULL\r\nGROUP BY clients.client_id\r\nORDER BY total_spent DESC\r\nLIMIT 1;" dataTable=value
databaseConnection" 变量为空。要使用这些脚本,请创建以下脚本:
defVar --name databasePath --type String
defVar --name path --type String
defVar --name sqliteConnection --type DbConnection
defVar --name result --type Numeric
defVar --name dataTable --type DataTable
defVar --name firstName --type String
defVar --name lastName --type String
defVar --name totalSpent --type Numeric
getSpecialFolder --folder "Desktop" path=value
setVar --name "${databasePath}" --value "${path}\\clients.db"
// Connects to database. Creates the database file if it doesn't exist.
executeScript --name "${path}\\connectToDb.wal" --parameters "{\"databasePath\":\"${databasePath}\"}" --output "{\"sqliteConnection\":\"${sqliteConnection}\"}"
// Checks if the database is populated.
executeScript --name "${path}\\checkDb.wal" --parameters "{\"databaseConnection\":\"${sqliteConnection}\"}" --output "{\"result\":\"${result}\"}"
// If the database is not populated, then it inserts data into the database. This avoids data duplication.
if --left "${result}" --operator "Greater_Than" --right 0 --negate
//Inserts data into the database. It only does that if the database has no data.
executeScript --name "${path}\\insertData.wal" --parameters "{\"databaseConnection\":\"${sqliteConnection}\"}"
endIf
// Gets the client that spent the highest amount in your coffee shop, with the amount spent.
executeScript --name "${path}\\queryDb.wal" --parameters "{\"databaseConnection\":\"${sqliteConnection}\"}" --output "{\"dataTable\":\"${dataTable}\"}"
mapTableRow --dataTable ${dataTable} --row 1 --mappings "[{\"Name\":\"first_name\",\"Number\":\"1\",\"Output\":\"${firstName}\"},{\"Name\":\"last_name\",\"Number\":\"2\",\"Output\":\"${lastName}\"},{\"Name\":\"total_spent\",\"Number\":\"3\",\"Output\":\"${totalSpent}\"}]"
// Prints the result of the query.
logMessage --message "${firstName} ${lastName} has spent a total of US$ ${totalSpent} in your coffee shop." --type "Info"
// The output is: "Jane Doe has spent a total of US$ 22.47 in your coffee shop."
此主脚本调用所有其他脚本以完成以下任务:
- 连接至该数据库。 如果数据库不存在,那么它将在桌面中创建
clients.db文件。 数据库连接变量由connectToDb.wal脚本返回,并由其他脚本用于连接到同一数据库。 - 检查是否填充了数据库。
- 如果未填充数据库,那么会将数据插入到数据库中。
- 查询数据库以获取在店铺中花费最高金额的客户。 它将返回客户机的名称以及所花费的总金额。
- 显示客户机的名称以及所花费的总金额。
示例 2
如果在运行时发生错误,那么可以使用 Handle Error 参数捕获错误消息。 如果启用了此参数,那么在运行时捕获的错误不会影响主脚本。 这些错误基本上会被忽略,并且脚本会正常继续运行,直到完成为止。 稍后可以记录和分析捕获的错误消息。
假设您的咖啡店现在有一个名为 Espresso Latte 的新产品,您希望跟踪新产品的销售情况。 为此,您必须对现有脚本进行少量更改。 在桌面中创建 espressoLatteQuery.wal 文件:
espressoLatteQuery.wal:
defVar --name dbConnection --type DbConnection --parameter
defVar --name result --type String --output
sqlExecuteScalar --connection ${dbConnection} --statement "SELECT SUM(order_items.quantity) FROM AS espresso_latte_quantity FROM order_items JOIN products ON order_items.product_id = products.product_id WHERE products.name = \"Espresso Latte\";" result=value
并编辑 executeScript.wal 文件:
executeScript.wal:
defVar --name databasePath --type String
defVar --name path --type String
defVar --name sqliteConnection --type DbConnection
defVar --name result --type Numeric
defVar --name resultLatte --type String
getSpecialFolder --folder "Desktop" path=value
setVar --name "${databasePath}" --value "${path}\\clients.db"
// Connects to database. Creates the database file if it doesn't exist.
executeScript --name "${path}\\connectToDb.wal" --parameters "{\"databasePath\":\"${databasePath}\"}" --output "{\"sqliteConnection\":\"${sqliteConnection}\"}"
// Checks if the database is populated.
executeScript --name "${path}\\checkDb.wal" --parameters "{\"databaseConnection\":\"${sqliteConnection}\"}" --output "{\"result\":\"${result}\"}"
// If the database is not populated, then it inserts data into the database. This avoids data duplication.
if --left "${result}" --operator "Greater_Than" --right 0 --negate
//Inserts data into the database. It only does that if the database has no data.
executeScript --name "${path}\\insertData.wal" --parameters "{\"databaseConnection\":\"${sqliteConnection}\"}"
endIf
// Gets the client that spent the highest amount in your coffee shop, with the amount spent.
executeScript --name "${path}\\espressoLatteQuery.wal" --parameters "{\"databaseConnection\":\"${sqliteConnection}\"}" --output "{\"result\":\"${resultLatte}\"}"
// Prints the result of the query.
logMessage --message "A total of ${resultLatte} Espresso Lattes have been sold in your coffe shop." --type "Info"
但是,数据库中没有与新产品相关的数据,如果您尝试运行 executeScript.wal 文件,那么不会返回任何内容,而您只会收到以下消息: "在您的咖啡店中总共销售了 Espresso Lattes"。 脚本不会失败,在更复杂的情况下,如果没有显式错误消息,这可能会成为难以找到解决方案的问题。
在此示例中,要演示错误处理的功能以及如何使用 IBM RPA捕获错误并处理这些错误,可以使用 抛出异常 (failTest) 命令来导致 "espressoLatteQuery.wal" 中的错误,并明确显示查询存在问题:
defVar --name dbConnection --type DbConnection --parameter
defVar --name result --type String --output
defVar --name errorMessage --type String --value "No Espresso Latte data found!"
defVar --name hasResult --type Boolean
sqlExecuteScalar --connection ${dbConnection} --statement "SELECT SUM(order_items.quantity) FROM AS espresso_latte_quantity FROM order_items JOIN products ON order_items.product_id = products.product_id WHERE products.name = \"Espresso Latte\";" result=value hasResult=hasresult
if --left "${hasResult}" --operator "Is_True" --negate
failTest --message "${errorMessage}"
endIf
如果您现在尝试运行 executeScript.wal ,那么会收到一条错误消息,阻止机器人完成该任务。 必须启用 Handle error 参数才能捕获错误消息:
defVar --name databasePath --type String
defVar --name path --type String
defVar --name sqliteConnection --type DbConnection
defVar --name result --type Numeric
defVar --name success --type Boolean
defVar --name errorMessage --type String
defVar --name resultLatte --type String
defVar --name errorLineNumber --type Numeric
defVar --name errorRoutine --type String
defVar --name error --type Error
getSpecialFolder --folder "Desktop" path=value
setVar --name "${databasePath}" --value "${path}\\clients.db"
// Connects to database. Creates the database file if it doesn't exist.
executeScript --name "${path}\\connectToDb.wal" --parameters "{\"databasePath\":\"${databasePath}\"}" --output "{\"sqliteConnection\":\"${sqliteConnection}\"}"
// Checks if the database is populated.
executeScript --name "${path}\\checkDb.wal" --parameters "{\"databaseConnection\":\"${sqliteConnection}\"}" --output "{\"result\":\"${result}\"}"
// If the database is not populated, then it inserts data into the database. This avoids data duplication.
if --left "${result}" --operator "Greater_Than" --right 0 --negate
//Inserts data into the database. It only does that if the database has no data.
executeScript --name "${path}\\insertData.wal" --parameters "{\"databaseConnection\":\"${sqliteConnection}\"}"
endIf
// Gets the client that spent the highest amount in your coffee shop, with the amount spent.
executeScript --handleError --name "${path}\\espressoLatteQuery.wal" --parameters "{\"databaseConnection\":\"${sqliteConnection}\"}" --output "{\"result\":\"${resultLatte}\"}" success=value errorMessage=errormessage errorLineNumber=linenumber errorRoutine=errorsubname error=error
// Prints the result of the query.
if --left "${success}" --operator "Is_True" --negate
setVar --name "${resultLatte}" --value 0
endIf
logMessage --message "A total of ${resultLatte} Espresso Lattes have been sold in your coffe shop." --type "Info"
该脚本不再失败,即使在其中一个被调用脚本中发生错误后,该脚本也将继续运行。 现在,您可以通过在 IBM RPA Studio的最后一行中添加断点来以 "调试" 方式检查错误消息,或者,如果在 IBM RPA Control Center中发布了机器人,那么可以检查机器人详细信息中的错误变量。 在此示例中,脚本将忽略错误消息并检查 "espressoLatteQuery.wal" 脚本是否成功运行。 如果没有,那么它会将值 "0" 赋给 resultLatte 变量以避免错误输出。