View a markdown version of this page

Step Functions examples using AWS CLI with Bash script - AWS Command Line Interface

Step Functions examples using AWS CLI with Bash script

The following code examples show you how to perform actions and implement common scenarios by using the AWS Command Line Interface with Bash script with Step Functions.

Scenarios are code examples that show you how to accomplish specific tasks by calling multiple functions within a service or combined with other AWS services.

Each example includes a link to the complete source code, where you can find instructions on how to set up and run the code in context.

Topics

Scenarios

The following code example shows how to:

  • Create an IAM role for Step Functions

  • Create your first state machine

  • Start your state machine execution

  • Clean up resources

AWS CLI with Bash script
Note

There's more on GitHub. Find the complete example and learn how to set up and run in the Sample developer tutorials repository.

#!/bin/bash # AWS Step Functions Getting Started Tutorial Script # This script creates and runs a Step Functions state machine based on the AWS Step Functions Getting Started tutorial # Parse command line arguments AUTO_CLEANUP=false while [[ $# -gt 0 ]]; do case $1 in --auto-cleanup) AUTO_CLEANUP=true shift ;; -h|--help) echo "Usage: $0 [--auto-cleanup] [--help]" echo " --auto-cleanup: Automatically clean up resources without prompting" echo " --help: Show this help message" exit 0 ;; *) echo "Unknown option: $1" echo "Use --help for usage information" exit 1 ;; esac done # Set up logging LOG_FILE="step-functions-tutorial.log" exec > >(tee -a "$LOG_FILE") 2>&1 echo "Starting AWS Step Functions Getting Started Tutorial..." echo "Logging to $LOG_FILE" # Check if jq is available for better JSON parsing if ! command -v jq &> /dev/null; then echo "WARNING: jq is not installed. Using basic JSON parsing which may be less reliable." echo "Consider installing jq for better error handling: brew install jq (macOS) or apt-get install jq (Ubuntu)" USE_JQ=false else USE_JQ=true fi # Use fixed region that supports Amazon Comprehend CURRENT_REGION="us-west-2" echo "Using fixed AWS region: $CURRENT_REGION (supports Amazon Comprehend)" # Set AWS CLI to use the fixed region for all commands export AWS_DEFAULT_REGION="$CURRENT_REGION" # Amazon Comprehend is available in us-west-2, so we can always enable it echo "Amazon Comprehend is available in region $CURRENT_REGION" SKIP_COMPREHEND=false # Function to check for API errors in JSON response check_api_error() { local response="$1" local operation="$2" if [[ "$USE_JQ" == "true" ]]; then # Use jq for more reliable JSON parsing if echo "$response" | jq -e '.Error' > /dev/null 2>&1; then local error_message=$(echo "$response" | jq -r '.Error.Message // .Error.Code // "Unknown error"') handle_error "$operation failed: $error_message" fi else # Fallback to grep-based detection if echo "$response" | grep -q '"Error":\|"error":'; then handle_error "$operation failed: $response" fi fi } # Function to wait for resource propagation with exponential backoff wait_for_propagation() { local resource_type="$1" local wait_time="${2:-10}" echo "Waiting for $resource_type to propagate ($wait_time seconds)..." sleep "$wait_time" } # Function to handle errors handle_error() { echo "ERROR: $1" echo "Resources created:" if [ -n "$STATE_MACHINE_ARN" ]; then echo "- State Machine: $STATE_MACHINE_ARN" fi if [ -n "$ROLE_NAME" ]; then echo "- IAM Role: $ROLE_NAME" fi if [ -n "$POLICY_ARN" ]; then echo "- IAM Policy: $POLICY_ARN" fi if [ -n "$STEPFUNCTIONS_POLICY_ARN" ]; then echo "- Step Functions Policy: $STEPFUNCTIONS_POLICY_ARN" fi echo "Attempting to clean up resources..." cleanup exit 1 } # Function to clean up resources cleanup() { echo "Cleaning up resources..." # Delete state machine if it exists if [ -n "$STATE_MACHINE_ARN" ]; then echo "Deleting state machine: $STATE_MACHINE_ARN" aws stepfunctions delete-state-machine --state-machine-arn "$STATE_MACHINE_ARN" || echo "Failed to delete state machine" fi # Detach and delete policies if they exist if [ -n "$POLICY_ARN" ] && [ -n "$ROLE_NAME" ]; then echo "Detaching Comprehend policy $POLICY_ARN from role $ROLE_NAME" aws iam detach-role-policy --role-name "$ROLE_NAME" --policy-arn "$POLICY_ARN" || echo "Failed to detach Comprehend policy" fi if [ -n "$STEPFUNCTIONS_POLICY_ARN" ] && [ -n "$ROLE_NAME" ]; then echo "Detaching Step Functions policy $STEPFUNCTIONS_POLICY_ARN from role $ROLE_NAME" aws iam detach-role-policy --role-name "$ROLE_NAME" --policy-arn "$STEPFUNCTIONS_POLICY_ARN" || echo "Failed to detach Step Functions policy" fi # Delete custom policies if they exist if [ -n "$POLICY_ARN" ]; then echo "Deleting Comprehend policy: $POLICY_ARN" aws iam delete-policy --policy-arn "$POLICY_ARN" || echo "Failed to delete Comprehend policy" fi if [ -n "$STEPFUNCTIONS_POLICY_ARN" ]; then echo "Deleting Step Functions policy: $STEPFUNCTIONS_POLICY_ARN" aws iam delete-policy --policy-arn "$STEPFUNCTIONS_POLICY_ARN" || echo "Failed to delete Step Functions policy" fi # Delete role if it exists if [ -n "$ROLE_NAME" ]; then echo "Deleting role: $ROLE_NAME" aws iam delete-role --role-name "$ROLE_NAME" || echo "Failed to delete role" fi # Remove temporary files echo "Removing temporary files" rm -f hello-world.json updated-hello-world.json sentiment-hello-world.json step-functions-trust-policy.json comprehend-policy.json stepfunctions-policy.json input.json sentiment-input.json } # Generate a random identifier for resource names RANDOM_ID=$(openssl rand -hex 4) ROLE_NAME="StepFunctionsHelloWorldRole-${RANDOM_ID}" POLICY_NAME="DetectSentimentPolicy-${RANDOM_ID}" STATE_MACHINE_NAME="MyFirstStateMachine-${RANDOM_ID}" echo "Using random identifier: $RANDOM_ID" echo "Role name: $ROLE_NAME" echo "Policy name: $POLICY_NAME" echo "State machine name: $STATE_MACHINE_NAME" # Step 1: Create the state machine definition echo "Creating state machine definition..." cat > hello-world.json << 'EOF' { "Comment": "A Hello World example of the Amazon States Language using a Pass state", "StartAt": "SetVariables", "States": { "SetVariables": { "Type": "Pass", "Result": { "IsHelloWorldExample": true, "ExecutionWaitTimeInSeconds": 10 }, "Next": "IsHelloWorldExample" }, "IsHelloWorldExample": { "Type": "Choice", "Choices": [ { "Variable": "$.IsHelloWorldExample", "BooleanEquals": true, "Next": "WaitState" } ], "Default": "FailState" }, "WaitState": { "Type": "Wait", "SecondsPath": "$.ExecutionWaitTimeInSeconds", "Next": "ParallelProcessing" }, "ParallelProcessing": { "Type": "Parallel", "Branches": [ { "StartAt": "Process1", "States": { "Process1": { "Type": "Pass", "Result": { "message": "Processing task 1" }, "End": true } } }, { "StartAt": "Process2", "States": { "Process2": { "Type": "Pass", "Result": { "message": "Processing task 2" }, "End": true } } } ], "Next": "CheckpointState" }, "CheckpointState": { "Type": "Pass", "Result": { "CheckpointMessage": "Workflow completed successfully!" }, "Next": "SuccessState" }, "SuccessState": { "Type": "Succeed" }, "FailState": { "Type": "Fail", "Error": "NotHelloWorldExample", "Cause": "The IsHelloWorldExample value was false" } } } EOF # Create IAM role trust policy echo "Creating IAM role trust policy..." cat > step-functions-trust-policy.json << 'EOF' { "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "states.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF # Create IAM role echo "Creating IAM role: $ROLE_NAME" ROLE_RESULT=$(aws iam create-role \ --role-name "$ROLE_NAME" \ --assume-role-policy-document file://step-functions-trust-policy.json) check_api_error "$ROLE_RESULT" "Create IAM role" echo "Role created successfully" # Get the role ARN if [[ "$USE_JQ" == "true" ]]; then ROLE_ARN=$(echo "$ROLE_RESULT" | jq -r '.Role.Arn') else ROLE_ARN=$(echo "$ROLE_RESULT" | grep "Arn" | cut -d'"' -f4) fi if [ -z "$ROLE_ARN" ]; then handle_error "Failed to extract role ARN" fi echo "Role ARN: $ROLE_ARN" # Create a custom policy for Step Functions echo "Creating custom policy for Step Functions..." cat > stepfunctions-policy.json << 'EOF' { "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "states:*" ], "Resource": "*" } ] } EOF # Create the policy echo "Creating Step Functions policy..." STEPFUNCTIONS_POLICY_RESULT=$(aws iam create-policy \ --policy-name "StepFunctionsPolicy-${RANDOM_ID}" \ --policy-document file://stepfunctions-policy.json) check_api_error "$STEPFUNCTIONS_POLICY_RESULT" "Create Step Functions policy" echo "Step Functions policy created successfully" # Get the policy ARN if [[ "$USE_JQ" == "true" ]]; then STEPFUNCTIONS_POLICY_ARN=$(echo "$STEPFUNCTIONS_POLICY_RESULT" | jq -r '.Policy.Arn') else STEPFUNCTIONS_POLICY_ARN=$(echo "$STEPFUNCTIONS_POLICY_RESULT" | grep "Arn" | cut -d'"' -f4) fi if [ -z "$STEPFUNCTIONS_POLICY_ARN" ]; then handle_error "Failed to extract Step Functions policy ARN" fi echo "Step Functions policy ARN: $STEPFUNCTIONS_POLICY_ARN" # Attach policy to the role echo "Attaching Step Functions policy to role..." ATTACH_RESULT=$(aws iam attach-role-policy \ --role-name "$ROLE_NAME" \ --policy-arn "$STEPFUNCTIONS_POLICY_ARN") if [ $? -ne 0 ]; then handle_error "Failed to attach Step Functions policy to role" fi # Wait for role to propagate (IAM changes can take time to propagate) wait_for_propagation "IAM role" 10 # Create state machine echo "Creating state machine: $STATE_MACHINE_NAME" SM_RESULT=$(aws stepfunctions create-state-machine \ --name "$STATE_MACHINE_NAME" \ --definition file://hello-world.json \ --role-arn "$ROLE_ARN" \ --type STANDARD) check_api_error "$SM_RESULT" "Create state machine" echo "State machine created successfully" # Get the state machine ARN if [[ "$USE_JQ" == "true" ]]; then STATE_MACHINE_ARN=$(echo "$SM_RESULT" | jq -r '.stateMachineArn') else STATE_MACHINE_ARN=$(echo "$SM_RESULT" | grep "stateMachineArn" | cut -d'"' -f4) fi if [ -z "$STATE_MACHINE_ARN" ]; then handle_error "Failed to extract state machine ARN" fi echo "State machine ARN: $STATE_MACHINE_ARN" # Step 2: Start the state machine execution echo "Starting state machine execution..." EXEC_RESULT=$(aws stepfunctions start-execution \ --state-machine-arn "$STATE_MACHINE_ARN" \ --name "hello001-${RANDOM_ID}") check_api_error "$EXEC_RESULT" "Start execution" echo "Execution started successfully" # Get the execution ARN if [[ "$USE_JQ" == "true" ]]; then EXECUTION_ARN=$(echo "$EXEC_RESULT" | jq -r '.executionArn') else EXECUTION_ARN=$(echo "$EXEC_RESULT" | grep "executionArn" | cut -d'"' -f4) fi if [ -z "$EXECUTION_ARN" ]; then handle_error "Failed to extract execution ARN" fi echo "Execution ARN: $EXECUTION_ARN" # Wait for execution to complete (the workflow has a 10-second wait state) echo "Waiting for execution to complete (15 seconds)..." sleep 15 # Check execution status echo "Checking execution status..." EXEC_STATUS=$(aws stepfunctions describe-execution \ --execution-arn "$EXECUTION_ARN") echo "Execution status: $EXEC_STATUS" # Step 3: Update state machine to process external input echo "Updating state machine to process external input..." cat > updated-hello-world.json << 'EOF' { "Comment": "A Hello World example of the Amazon States Language using a Pass state", "StartAt": "SetVariables", "States": { "SetVariables": { "Type": "Pass", "Parameters": { "IsHelloWorldExample.$": "$.hello_world", "ExecutionWaitTimeInSeconds.$": "$.wait" }, "Next": "IsHelloWorldExample" }, "IsHelloWorldExample": { "Type": "Choice", "Choices": [ { "Variable": "$.IsHelloWorldExample", "BooleanEquals": true, "Next": "WaitState" } ], "Default": "FailState" }, "WaitState": { "Type": "Wait", "SecondsPath": "$.ExecutionWaitTimeInSeconds", "Next": "ParallelProcessing" }, "ParallelProcessing": { "Type": "Parallel", "Branches": [ { "StartAt": "Process1", "States": { "Process1": { "Type": "Pass", "Result": { "message": "Processing task 1" }, "End": true } } }, { "StartAt": "Process2", "States": { "Process2": { "Type": "Pass", "Result": { "message": "Processing task 2" }, "End": true } } } ], "Next": "CheckpointState" }, "CheckpointState": { "Type": "Pass", "Result": { "CheckpointMessage": "Workflow completed successfully!" }, "Next": "SuccessState" }, "SuccessState": { "Type": "Succeed" }, "FailState": { "Type": "Fail", "Error": "NotHelloWorldExample", "Cause": "The IsHelloWorldExample value was false" } } } EOF # Update state machine echo "Updating state machine..." UPDATE_RESULT=$(aws stepfunctions update-state-machine \ --state-machine-arn "$STATE_MACHINE_ARN" \ --definition file://updated-hello-world.json \ --role-arn "$ROLE_ARN") check_api_error "$UPDATE_RESULT" "Update state machine" echo "State machine updated successfully" # Create input file echo "Creating input file..." cat > input.json << 'EOF' { "wait": 5, "hello_world": true } EOF # Start execution with input echo "Starting execution with input..." EXEC2_RESULT=$(aws stepfunctions start-execution \ --state-machine-arn "$STATE_MACHINE_ARN" \ --name "hello002-${RANDOM_ID}" \ --input file://input.json) check_api_error "$EXEC2_RESULT" "Start execution with input" echo "Execution with input started successfully" # Get the execution ARN if [[ "$USE_JQ" == "true" ]]; then EXECUTION2_ARN=$(echo "$EXEC2_RESULT" | jq -r '.executionArn') else EXECUTION2_ARN=$(echo "$EXEC2_RESULT" | grep "executionArn" | cut -d'"' -f4) fi if [ -z "$EXECUTION2_ARN" ]; then handle_error "Failed to extract execution ARN" fi echo "Execution ARN: $EXECUTION2_ARN" # Wait for execution to complete (the workflow has a 5-second wait state) echo "Waiting for execution to complete (10 seconds)..." sleep 10 # Check execution status echo "Checking execution status..." EXEC2_STATUS=$(aws stepfunctions describe-execution \ --execution-arn "$EXECUTION2_ARN") echo "Execution status: $EXEC2_STATUS" # Step 4: Integrate Amazon Comprehend for sentiment analysis (if available) if [[ "$SKIP_COMPREHEND" == "false" ]]; then echo "Creating policy for Amazon Comprehend access..." cat > comprehend-policy.json << 'EOF' { "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "comprehend:DetectSentiment" ], "Resource": "*" } ] } EOF # Create policy echo "Creating IAM policy: $POLICY_NAME" POLICY_RESULT=$(aws iam create-policy \ --policy-name "$POLICY_NAME" \ --policy-document file://comprehend-policy.json) check_api_error "$POLICY_RESULT" "Create Comprehend policy" echo "Comprehend policy created successfully" # Get policy ARN if [[ "$USE_JQ" == "true" ]]; then POLICY_ARN=$(echo "$POLICY_RESULT" | jq -r '.Policy.Arn') else POLICY_ARN=$(echo "$POLICY_RESULT" | grep "Arn" | cut -d'"' -f4) fi if [ -z "$POLICY_ARN" ]; then handle_error "Failed to extract policy ARN" fi echo "Policy ARN: $POLICY_ARN" # Attach policy to role echo "Attaching policy to role..." ATTACH2_RESULT=$(aws iam attach-role-policy \ --role-name "$ROLE_NAME" \ --policy-arn "$POLICY_ARN") if [ $? -ne 0 ]; then handle_error "Failed to attach policy to role" fi # Create updated state machine definition with sentiment analysis echo "Creating updated state machine definition with sentiment analysis..." cat > sentiment-hello-world.json << 'EOF' { "Comment": "A Hello World example with sentiment analysis", "StartAt": "SetVariables", "States": { "SetVariables": { "Type": "Pass", "Parameters": { "IsHelloWorldExample.$": "$.hello_world", "ExecutionWaitTimeInSeconds.$": "$.wait", "FeedbackComment.$": "$.feedback_comment" }, "Next": "IsHelloWorldExample" }, "IsHelloWorldExample": { "Type": "Choice", "Choices": [ { "Variable": "$.IsHelloWorldExample", "BooleanEquals": true, "Next": "WaitState" } ], "Default": "DetectSentiment" }, "WaitState": { "Type": "Wait", "SecondsPath": "$.ExecutionWaitTimeInSeconds", "Next": "ParallelProcessing" }, "ParallelProcessing": { "Type": "Parallel", "Branches": [ { "StartAt": "Process1", "States": { "Process1": { "Type": "Pass", "Result": { "message": "Processing task 1" }, "End": true } } }, { "StartAt": "Process2", "States": { "Process2": { "Type": "Pass", "Result": { "message": "Processing task 2" }, "End": true } } } ], "Next": "CheckpointState" }, "CheckpointState": { "Type": "Pass", "Result": { "CheckpointMessage": "Workflow completed successfully!" }, "Next": "SuccessState" }, "DetectSentiment": { "Type": "Task", "Resource": "arn:aws:states:::aws-sdk:comprehend:detectSentiment", "Parameters": { "LanguageCode": "en", "Text.$": "$.FeedbackComment" }, "Next": "SuccessState" }, "SuccessState": { "Type": "Succeed" } } } EOF # Wait for IAM changes to propagate wait_for_propagation "IAM changes" 10 # Update state machine echo "Updating state machine with sentiment analysis..." UPDATE2_RESULT=$(aws stepfunctions update-state-machine \ --state-machine-arn "$STATE_MACHINE_ARN" \ --definition file://sentiment-hello-world.json \ --role-arn "$ROLE_ARN") check_api_error "$UPDATE2_RESULT" "Update state machine with sentiment analysis" echo "State machine updated with sentiment analysis successfully" # Create input file with feedback comment echo "Creating input file with feedback comment..." cat > sentiment-input.json << 'EOF' { "hello_world": false, "wait": 5, "feedback_comment": "This getting started with Step Functions workshop is a challenge!" } EOF # Start execution with sentiment analysis input echo "Starting execution with sentiment analysis input..." EXEC3_RESULT=$(aws stepfunctions start-execution \ --state-machine-arn "$STATE_MACHINE_ARN" \ --name "hello003-${RANDOM_ID}" \ --input file://sentiment-input.json) check_api_error "$EXEC3_RESULT" "Start execution with sentiment analysis" echo "Execution with sentiment analysis started successfully" # Get the execution ARN if [[ "$USE_JQ" == "true" ]]; then EXECUTION3_ARN=$(echo "$EXEC3_RESULT" | jq -r '.executionArn') else EXECUTION3_ARN=$(echo "$EXEC3_RESULT" | grep "executionArn" | cut -d'"' -f4) fi if [ -z "$EXECUTION3_ARN" ]; then handle_error "Failed to extract execution ARN" fi echo "Execution ARN: $EXECUTION3_ARN" # Wait for execution to complete echo "Waiting for execution to complete (5 seconds)..." sleep 5 # Check execution status echo "Checking execution status..." EXEC3_STATUS=$(aws stepfunctions describe-execution \ --execution-arn "$EXECUTION3_ARN") echo "Execution status: $EXEC3_STATUS" else echo "Skipping Amazon Comprehend integration (not available in $CURRENT_REGION)" EXECUTION3_ARN="" fi # Display summary of resources created echo "" echo "===========================================" echo "RESOURCES CREATED" echo "===========================================" echo "State Machine: $STATE_MACHINE_ARN" echo "IAM Role: $ROLE_NAME" echo "Step Functions Policy: StepFunctionsPolicy-${RANDOM_ID} ($STEPFUNCTIONS_POLICY_ARN)" if [[ "$SKIP_COMPREHEND" == "false" ]]; then echo "Comprehend Policy: $POLICY_NAME ($POLICY_ARN)" fi echo "Executions:" echo " - hello001-${RANDOM_ID}: $EXECUTION_ARN" echo " - hello002-${RANDOM_ID}: $EXECUTION2_ARN" if [[ "$SKIP_COMPREHEND" == "false" ]]; then echo " - hello003-${RANDOM_ID}: $EXECUTION3_ARN" fi echo "===========================================" # Prompt for cleanup echo "" echo "===========================================" echo "CLEANUP CONFIRMATION" echo "===========================================" if [[ "$AUTO_CLEANUP" == "true" ]]; then echo "Auto-cleanup enabled. Cleaning up resources..." cleanup echo "All resources have been cleaned up." else echo "Do you want to clean up all created resources? (y/n): " read -r CLEANUP_CHOICE if [[ "$CLEANUP_CHOICE" =~ ^[Yy]$ ]]; then cleanup echo "All resources have been cleaned up." else echo "Resources were not cleaned up. You can manually clean them up later." echo "To view the state machine in the AWS console, visit:" echo "https://console.aws.amazon.com/states/home?region=$CURRENT_REGION" fi fi echo "Script completed successfully!"