Run a shell command on a device

Check that a device supports shell commands, find a predefined command for its device type, send the command as a c8y_Command operation, and read the result that the device returns.

Use with an AI agent

This page is the agent skill cumulocity-run-shell-command. Save it as cumulocity-run-shell-command/SKILL.md in the skills folder of your agent: .agents/skills/ for Codex, GitHub Copilot, Cursor, and Gemini CLI, or .claude/skills/ for Claude Code. It builds on cumulocity-authentication: install that skill too.

Many devices accept commands in their own command language, for example AT commands for modems or scripts on gateways. To run such a command, you send the device a c8y_Command operation with the command text. The device runs the command, sets the operation to SUCCESSFUL, and writes the result into the same operation. The format and the meaning of the command text are up to the device integration. The operation goes through the same statuses as any other operation, see Send an operation to a device.

In the Device Management application, you run commands in the Shell tab of the device, see Shell. For the device side, see Shell in the fragment library.

The following cases need a different procedure:

  • LWM2M devices: A device with the fragment c8y_IsLwm2mDevice accepts only a fixed set of commands, see Handling LWM2M shell commands.
  • Services: To stop, start, or restart a software service on a device, send a service command instead, see Service commands.
Important
When you operate machinery remotely, make sure that all remote operations follow the safety standards and do not cause any harm.
Requirements

SKILLS:

ROLES & PERMISSIONS:

  • To read the device and the predefined commands: ROLE_INVENTORY_READ
  • To send the command: ROLE_DEVICE_CONTROL_ADMIN
  • To read the result: ROLE_DEVICE_CONTROL_READ

The examples use <device_id> for the ID of the device and <operation_id> for the ID of the operation.

To check that the device supports shell commands

Send a Retrieve a specific managed object request:

GET /inventory/managedObjects/<device_id>

The platform returns HTTP 200 and the managed object. Check the following:

  • The fragment c8y_IsDevice is present.
  • The array c8y_SupportedOperations contains "c8y_Command".
  • The fragment c8y_IsLwm2mDevice is not present.

If c8y_Command is missing, do not send a command. No agent executes the operation. Do not send the operation to find out whether the device supports it.

To find a predefined command

Predefined commands for a device type are stored in managed objects of type c8y_DeviceShellTemplate. The Device Management application shows them as Predefined commands in the Shell tab. Skip this procedure if you already have the command text.

Send a Retrieve all managed objects request with a query for the device type, here c8y_Linux:

GET /inventory/managedObjects?query=$filter=(type eq 'c8y_DeviceShellTemplate' and deviceType eq 'c8y_Linux')&pageSize=1000

Encode the spaces in the query as %20. The platform returns HTTP 200 and the matching objects in the managedObjects array. Each object has a templates array. Each entry of this array has a name and the command text. Use the text of one entry as the command text.

If the managedObjects array is empty, no predefined commands exist for this device type. Use your own command text.

To send the command

Send a Create an operation request:

POST /devicecontrol/operations
Content-Type: application/json
Accept: application/json

{
  "deviceId": "<device_id>",
  "description": "Execute shell command",
  "c8y_Command": {
    "text": "get sw.version; get hw.version"
  }
}

The property c8y_Command.text is mandatory and contains the command text.

The platform returns HTTP 201 and the operation with its id and "status": "PENDING". Note the id as <operation_id>.

If the platform returns HTTP 422, the device does not exist, or neither the device nor one of its parent devices is an agent.

To read the result

Send a Retrieve a specific operation request:

GET /devicecontrol/operations/<operation_id>

Repeat the request every 5 seconds until the status is SUCCESSFUL or FAILED, for example for at most 2 minutes:

  • SUCCESSFUL: The property c8y_Command.result contains the result of the command as a string, for example "1.2.3; 9.8.7". If the property is missing, the device completed the operation without a result.
  • FAILED: The failureReason property describes why the command failed.

If the operation is still PENDING or EXECUTING after the timeout, see To follow the status of the operation. To cancel an operation that stays PENDING, see To cancel a pending operation.