Enclosing shortcodes create line breaks

If you want to just strip the <br /> from the content then you could modify your function to replace that signature with an empty string. It feels like a dirty hack, but it’s working for me.

It’s worth noting that my Chrome tools show <br> but the actual code is rendering <br /> which is what the expression is checking against.

//[rezept]
function rezept_func( $atts, $content = null ) {

    // remove '<br />'
    $no_br = preg_replace( "/(<br\s\/>)/", "", do_shortcode( $content ) );
    return '<div class="drl-rezept-wrapper">' . $no_br . '</div>';
}

add_shortcode( 'rezept', 'rezept_func' );

function rezept_zutaten_func( $atts, $content = null ) {

    // remove '<br />'
    $no_br = preg_replace( "/(<br\s\/>)/", "", $content );
    return '<div class="drl-rezept-left">' . $no_br . '</div>';
}

add_shortcode( 'rezept-zutaten', 'rezept_zutaten_func' );

The reason this is happening is there is a wpautop filter on the $content before it reaches your shortcode. You can actually disable all extra <br /> and <p> tags by adding:

remove_filter( 'the_content', 'wpautop' );

And you can enable the p without br by registering our own filter:

add_filter( 'the_content', 'wpautop_no_br' );

function wpautop_no_br ($content, $br){
    return wpautop($content, false);
}

Although if you were to disable wpautop then you’re affecting more than just your shortcode which is not recommended. To see the difference take a look at the output from these blocks.

echo '<pre>RAW</pre><pre>'
     . get_post( get_the_ID() )->post_content
     . '</pre>';

echo '<pre>Filtered</pre><pre>'
     . wpautop( get_post( get_the_ID() )->post_content )
     . '</pre>';

echo '<pre>Filtered - No BR</pre><pre>'
     . wpautop( get_post( get_the_ID() )->post_content, false )
     . '</pre>';