Pass variable to nested shortcode

I assume you just pass the content of ct_training_group to another call of do_shortcode()? You can’t pass extra parameters to it, so if you don’t want to use global state variables, you could always replace the current shortcode handler for ct_training with one that doesn’t add the extra <ul>. It seems there is no cache for the handlers, so there will not be a performance penalty.

add_shortcode('ct_training', 'ct_training_full');
function ct_training_full($attr, $content)
{
    return '<ul>' . ct_training_item($attr, $content) . '</ul>';
}

function ct_training_item($attr, $content)
{
    return '<li>CT Training</li>';
}

add_shortcode('ct_training_group', 'ct_training_group_handler');
function ct_training_group_handler($attr, $content)
{
    $output="<h3>CT Training group</h3>";
    $output .= '<ul>';
    // Redefine the sub-code
    add_shortcode('ct_training', 'ct_training_item');
    $output .= do_shortcode($content);
    // Reset the sub-code
    add_shortcode('ct_training', 'ct_training_full');
    $output .= '</ul>';
    return $output;
}