Passing values between enclosing and enclosed shortcodes

You can try this plugin:

/**
 * Plugin Name: My Boxes Shortcode 
 * Author: birgire
 * Author URI: http://wordpress.stackexchange.com/a/121423/26350
 */

add_action( 'plugins_loaded', array( 'My_Boxes_Shortcode', 'get_instance' ) );

if( ! class_exists( 'My_Boxes_Shortcode' ) )
{

    class My_Boxes_Shortcode
    {
        static private $instance = NULL;

        static public function get_instance() 
        {        
            if ( NULL === self::$instance )
                self::$instance = new self;

            return self::$instance;            
        }

        public function __construct() 
        {
            add_shortcode( 'boxes', array( $this, 'boxes_callback' ) );   
            add_shortcode( 'box',   array( $this, 'box_callback'   ) );   
        }        

        public function box_callback( $atts, $content ) 
        {        
            $atts = shortcode_atts( 
                        array(
                            'class'     => 'box',
                    ), $atts, 'my_box_shortcode' );

            // input
            $content               = esc_textarea( trim( $content ) );
            $atts['class']         = esc_attr( $atts['class'] );

            // output                       
            return sprintf( '<div class="%s">%s</div>', $atts['class'], $content );             
        }

        public function boxes_callback( $atts, $content ) 
        {        
            $atts = shortcode_atts( 
                        array(
                            'class'     => 'boxes',
                            'per_row'   => '3',
                    ), $atts, 'my_boxes_shortcode' );

            // input
            $content               = str_replace( '<br />', ' ', $content );
            $atts['class']         = esc_attr( $atts['class'] );
            $atts['per_row']       = (int) $atts['per_row'];

            // if per_row is not positive then force it to the default value.
            $atts['per_row'] = ( 1 > $atts['per_row'] )? 3 : $atts['per_row'];

            // split the content into boxes
            $content = str_replace( '[/box]', '[/box]<!--x-->', $content ); 
            $boxes = explode( '<!--x-->', do_shortcode( $content ) );

            // output           
            $html="";

            // add a div wrapper around each row
            if( 0 < count( $boxes ) )
            {
                $html .= '<div class="row-wrapper">';

                foreach( $boxes as $i => $box )
                {           
                    $html .= $box;

                    // inject the row seperator
                    if(  ( $atts['per_row'] - 1 ) === ( $i % $atts['per_row'] ) )
                        $html .= '</div><div class="row-wrapper">';
                }
                $html .= '</div>';

                // remove the last row wrapper if it's empty
                if( 1 === ( count( $boxes ) % $atts['per_row'] ) )
                    $html = substr( $html, 0, (-1) * strlen( '<div class="row-wrapper"> </div> ' ) );
            }

            return sprintf( '<!-- start boxes wrapper: -->
                                     <div class="%s">%s</div>
                             <!-- end boxes wrapper -->', $atts['class'], $html );                      
        }

    } // end class 

} // end if class ! exists

I guess there are much better ways to do this, but you can adjust the class to your needs.

Then this kind of shortcode setup:

[boxes class="myboxes" per_row="3"]
    [box class="box first"]foo[/box]
    [box]bar[/box]
    [box]baz[/box]
    [box class="box last"]quux[/box]
[/boxes]

should give you the following HTML:

<!-- start boxes wrapper: -->
<div class="myboxes">
    <div class="row-wrapper"> 
        <div class="box first">foo</div> 
        <div class="box">bar</div> 
        <div class="box">baz</div> 
    </div>
    <div class="row-wrapper"> 
        <div class="box last">quux</div>
    </div>
</div>
<!-- end boxes wrapper -->