LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Call a function within a function in Bash Script (https://www.linuxquestions.org/questions/linux-newbie-8/call-a-function-within-a-function-in-bash-script-4175636977/)

bluethundr 08-23-2018 02:07 PM

Call a function within a function in Bash Script
 
I have a very simple function that prints a banner when the work of the script is complete. This is all it does:

Code:

end_banner() { 
        echo "*********************************************"
        echo "*        Your work in AWS is done          *"
        echo "*********************************************"
    }

But when I call that function from the other functions in my script, it does not get invoked.

For example I try to call the end_banner function from this function:

Code:

create_instance() {
      ...lines that do stuff...
      end_banner
    }

And the output in the end_banner function does not get printed out. It doesn't even show up when I run the script with bash -x. It's like that end_banner line isn't even there.

Here's a minimal version of my entire script, with full versions of end_banner, create_volume and create_instance:


Code:

    end_banner() {
    echo "*********************************************"
    echo "*        Your work in AWS is done          *"
    echo "*********************************************"
    }

    main() {
      # 1 Lab
      if [ "$accountnumber" == 123456789 ]; then
        "$user_action"
        return
      fi
   
    }
   
    choose_account() {
      echo "1 Lab"
      echo "Please enter a number for the account you want to work in."
      printf "Choose AWS Account: "
      read -r aws_account_number
      echo
    # 1 Lab
    if [ "$aws_account_number" -eq 1 ]; then
        aws_account="Company Lab"
        aws_key="lab"
        accountnumber=123456789
        return
    fi
    }
   
    choose_action() {
      echo "These are the actions possible in AWS: "
      echo
      echo "5 Create Volume"
      echo "20 Create AWS Instance"
      echo; echo
      printf "Enter an action in AWS: "
      read -r action
      echo
      # 5 Create AWS Volume
      if [ "$action" -eq "5" ]; then
        user_action=create_volume
        return
      # 20 Create AWS Instance
      elif [ "$action" -eq "20" ]; then
        user_action=create_instance
        return
      fi
   
    }
   
    create_volume() {
    echo "*  Create an EBS volume in AWS $aws_account  *"
    echo
   
    printf "Enter a volume name: "
    read -r volume_name
    echo
        # Lab
        if [ "$accountnumber" -eq 123456789 ]; then
        echo "Availability Zones for $aws_account"
        echo "AZ 1: us-east-1a"
        echo "AZ 2: us-east-1b"
        echo
        fi
   
        #Availability Zones
        printf "Enter availability zone\\nExample. Type out: us-east-1a\\n"
        printf "AZ: "
        read -r availability_zone
        echo
     
        # Volume Size
        printf "Enter size: "
        read -r volume_size
        echo
   
        # Create from snapshot
        printf "Create from snapshot (y/n): "
        read -r from_snapshot
        echo
        if [[ "$from_snapshot" = [Yy] ]]; then
          printf "Enter Snapshot ID: "
                read -r snapshot_id
          echo
        else
          printf "No Snapshot Required\\n\\n"
        fi
     
        # Add encryption
        printf "Encrypted (y/n): "
        read -r encrypted
        echo
        if [[ "$encrypted" = [Yy] ]]; then
          printf "Enter KMS Key ID: "
                read -r kms_key_id
          echo
        else
          printf "No Encryption Required\\n\\n"
        fi
     
        # Set the Owner / Application / Engagement
        printf "Enter the Owner Name: "
        read -r owner
        echo
        printf "Enter the application name: "
        read -r application
        echo
        printf "Enter the engagement code: "
        read -r engagement
        echo
     
      # Create the volume based on the above
            if [[ "$from_snapshot" = [Yy] ]]; then
                    #Create EBS Volume from Snapshot"
                    volume_id=$(aws ec2 create-volume --size "$volume_size" --availability-zone "$availability_zone"  --snapshot-id "$snapshot_id" --volume-type gp2  --tag-specifications "ResourceType=volume,Tags=[{Key=\"Name\",Value=\"$volume_name\"},{Key=Engagement,Value=\"$engagement\"},{Key=\"Owner\", Value=\"$owner\"},{Key=\"Application\", Value=\"$application\"}]" --profile="$aws_key" | jq -r '.VolumeId')
                    return
            elif [[ "$encrypted" = [Yy] ]]; then
                    #Create EBS Volume with KMS Key"
                    volume_id=$(aws ec2 create-volume --size "$volume_size" --availability-zone "$availability_zone" --kms-key-id="$kms_key_id" --volume-type gp2  --tag-specifications "ResourceType=volume,Tags=[{Key=\"Name\",Value=\"$volume_name\"},{Key=\"Engagement\",Value=\"$engagement\"},{Key=\"Owner\", Value=\"$owner\"},{Key=\"Application\", Value=\"$application\"}]" --profile="$aws_key" | jq -r '.VolumeId')
            elif [[ "$from_snapshot" = [Yy] && "$encrypted" = [Yy] ]]; then
                    #Create EBS Volume from snapshot with KMS Key"
                    volume_id=$(aws ec2 create-volume --size "$volume_size" --availability-zone "$availability_zone"  --snapshot-id "$snapshot_id" --volume-type gp2 --profile="$aws_key" --tag-specifications "ResourceType=volume,Tags=[{\"Key=Name,Value=\"$volume_name\"},{Key=\"Engagement\",Value=\"$engagement\"},{Key=\"Owner\", Value=\"$owner\"},{Key=\"Application\", Value=\"$application\"}]" --profile="$aws_key" |  jq -r '.VolumeId')
            else
                    #Create a plain volume without snapshot and encryption
                    volume_id=$(aws ec2 create-volume --size "$volume_size" --availability-zone "$availability_zone" --volume-type gp2 --tag-specifications "ResourceType=volume,Tags=[{Key=\"Name\",Value=\"$volume_name\"},{Key=\"Engagement\",Value=\"$engagement\"},{Key=\"Owner\", Value=\"$owner\"},{Key=\"Application\", Value=\"$application\"}]" --profile="$aws_key" | jq -r '.VolumeId')
            fi
      sleep 10
            echo "Volume created is:  $volume_id"
      echo
      local VOLID=$1
      eval $VOLID="$volume_id"
    }
   
   
   
    create_instance() {
   
   
    echo "  Create An Instance in AWS $aws_account"
   
   
    printf "Enter Platform\\n"
    printf "Example: Windows / Linux\\n"
    printf "Plaform: "
    read -r platform
   
    # using LAB  amis for now
    if [ \( "$platform" = "Windows" \) ] || [ \( "$platform" = "windows" \) ]; then
      ami="ami-03bfe6d8e0e60051c"
    elif [ \( "$platform" = "Linux" \) ]  || [ \( "$platform"  = "linux" \) ]; then
      ami="ami-4fb38358"
    else
      printf "That is not a valid choice."
    fi
   
    printf "Enter an Instance Type: "
    read -r instance_type
   
    printf "Enter Number of Instances: "
    read -r num_instances
   
    printf "Enter a Subnet ID: "
    read -r subnet_id
   
    printf "Enter Security Group ID: "
    read -r security_group
   
    printf "Enter a key name: "
    read -r key_name
   
    printf "Enter a server name: "
    read -r name_tag
   
    printf "Enter an application name: "
    read -r application_tag
   
    printf "Enter an engagement code: "
    read -r engagement_tag
   
    printf "Enter an owner name: "
    read -r owner_tag
   
    printf "Enter a role: "
    read -r role_tag
   
    ## Launch the instance
    tag_instance_id=$(aws ec2 run-instances --count "$num_instances" --image-id "$ami" --instance-type "$instance_type" --key-name "$key_name" --subnet-id "$subnet_id" --security-group-ids "$security_group"  --profile="$aws_key" | jq -r '.Instances[].InstanceId')
    # Get volume ID and device name
    root_vol=$(aws ec2 describe-instances --instance-ids "$tag_instance_id" --profile="$aws_key" | jq -r '.Reservations[].Instances[].BlockDeviceMappings[].Ebs.VolumeId')
    root_vol_device_name=$(aws ec2 describe-volumes --volume-ids "$root_vol" --profile="$aws_key" | jq -r '.Volumes[].Attachments[].Device')
    az=$(aws ec2 describe-instances --instance-ids "$tag_instance_id" --profile="$aws_key" | jq -r '.Reservations[].Instances[].Placement.AvailabilityZone')
   
    echo
    printf "Instance ID: %s has been created in Availability Zone: %s\\n" "$tag_instance_id" "$az"
    printf "Wait till the instance is created to tag it.\\n"
   
    sleep 15
   
    # Tagging the new instance
    aws ec2 create-tags --resources "$tag_instance_id" --tags Key=Name,Value="$name_tag"  Key=Application,Value="$application_tag" Key=Engagement,Value="$engagement_tag" Key=Owner,Value="$owner_tag" Key=Role,Value="$role_tag" --profile="$aws_key"
   
    ## Tagging the Root Volume - fixed tags
    aws ec2 create-tags --resources "$root_vol" --tags Key=Name,Value="$name_tag root volume"  Key=DeviceName,Value="$root_vol_device_name" Key=Application,Value="$application_tag" Key=Engagement,Value="$engagement_tag" Key=Owner,Value="$owner_tag" Key=Role,Value="$role_tag" --profile="$aws_key"
   
    printf  "The instance %s now has the following tags:\\n" "$tag_instance_id"
    printf "Host Name: %s\\n" "$name_tag"
    printf "Application: %s\\n" "$application_tag"
    printf "Engagement: %s\\n" "$engagement_tag"
    printf "Owner: %s\\n" "$owner_tag"
    printf "Role: %s\\n" "$role_tag"
   
    echo
    printf "Do you need additional volumes (y/n): "
    read -r vol_answer
    if [[ "$vol_answer" = [Yy] ]]; then
      printf "Number of volumes to add: "
      read -r num_volumes
      volumes=()
      devices=( {f..z} )
      for (( i=0; i < num_volumes; i++ )); do
        CURID=''
        create_volume 'CURID'
        volumes[$i]=${CURID}
          printf "Attach volume ID: %s\\n" "${volumes[i]}"
          if [ \( "$platform" = "Windows" \) ] || [ \( "$platform" = "windows" \) ]; then
            device="/dev/sd${devices[i]}"
            aws ec2 attach-volume --volume-id "${volumes[i]}" --instance-id "$tag_instance_id" --device "$device" --profile="$aws_key" | jq '.'
            aws ec2 create-tags --resources "${volumes[i]}" --tags Key=Name,Value="$name_tag volume"  Key=DeviceName,Value="$device" Key=Application,Value="$application_tag" Key=Engagement,Value="$engagement_tag" Key=Owner,Value="$owner_tag" Key=Role,Value="$role_tag" --profile="$aws_key"
          elif [ \( "$platform" = "Linux" \) ]  || [ \( "$platform"  = "linux" \) ]; then
            device="/dev/xvd${devices[i]}"
            aws ec2 attach-volume --volume-id "${volumes[i]}" --instance-id "$tag_instance_id" --device "$device" --profile="$aws_key" | jq '.'
            aws ec2 create-tags --resources "${volumes[i]}" --tags Key=Name,Value="$name_tag volume"  Key=DeviceName,Value="$device" Key=Application,Value="$application_tag" Key=Engagement,Value="$engagement_tag" Key=Owner,Value="$owner_tag" Key=Role,Value="$role_tag" --profile="$aws_key"
          else
            printf "That is not a valid choice.\\n"
          fi 
      done
      return
    elif [[ "$vol_answer" = [Nn] ]]; then
      printf "Ok. No added volumes will be created.\\n"
    else
      printf "Input is incorrect.\\n"
    fi
    end_banner
    }
   
    choose_action
    choose_account
    main "$@"

What am I doing wrong?

rtmistler 08-23-2018 02:20 PM

You're not doing anything wrong, that works for me.

Perhaps turn on debugging to determine what is happening.

rtmistler 08-23-2018 02:22 PM

Code:

$ cat test.sh
end() {
    echo "1"
}

create() {
    echo "2"
    end
}

create

Output:
Code:

$ ./test
2
1


bluethundr 08-23-2018 03:08 PM

I've found the culprit.

In this part of create_instances, I had a return that was causing the program to exit before the end_banner function was called:

Code:

for (( i=0; i < num_volumes; i++ )); do
        CURID=''
        create_volume 'CURID'
        volumes[$i]=${CURID}
          printf "Attach volume ID: %s\\n" "${volumes[i]}"
          if [ \( "$platform" = "Windows" \) ] || [ \( "$platform" = "windows" \) ]; then
            device="/dev/sd${devices[i]}"
            aws ec2 attach-volume --volume-id "${volumes[i]}" --instance-id "$tag_instance_id" --device "$device" --profile="$aws_key" 2>&1 | sed -e 's/An error occurred (InvalidVolume.ZoneMismatch) //g' | jq '.'
            aws ec2 create-tags --resources "${volumes[i]}" --tags Key=Name,Value="$name_tag volume"  Key=DeviceName,Value="$device" Key=Application,Value="$application_tag" Key=Engagement,Value="$engagement_tag" Key=Owner,Value="$owner_tag" Key=Role,Value="$role_tag" --profile="$aws_key"
          elif [ \( "$platform" = "Linux" \) ]  || [ \( "$platform"  = "linux" \) ]; then
            device="/dev/xvd${devices[i]}"
            aws ec2 attach-volume --volume-id "${volumes[i]}" --instance-id "$tag_instance_id" --device "$device" --profile="$aws_key" 2>&1 | sed -e 's/An error occurred (InvalidVolume.ZoneMismatch) //g' | jq '.'
            aws ec2 create-tags --resources "${volumes[i]}" --tags Key=Name,Value="$name_tag volume"  Key=DeviceName,Value="$device" Key=Application,Value="$application_tag" Key=Engagement,Value="$engagement_tag" Key=Owner,Value="$owner_tag" Key=Role,Value="$role_tag" --profile="$aws_key"
          else
            printf "That is not a valid choice.\\n"
          fi
      return
      done

I removed that return line and the script now works as planned.


All times are GMT -5. The time now is 09:43 AM.