Wordpress - Create a shortcode to display custom post types with a specific taxonomy

First off, it's always good to register shortcode during init versus just in your general functions.php file. At the very least add_shortcode() should be in init. Anyway, let's begin!

Whenever you use add_shortcode() the first parameter is going to be the name of the shortcode and the 2nd will be the callback function. This means that:

[products line="prime"]

Should be instead:

[produtos line="prime"]

So far we have this:

/**
 * Register all shortcodes
 *
 * @return null
 */
function register_shortcodes() {
    add_shortcode( 'produtos', 'shortcode_mostra_produtos' );
}
add_action( 'init', 'register_shortcodes' );

/**
 * Produtos Shortcode Callback
 * - [produtos]
 * 
 * @param Array $atts
 *
 * @return string
 */
function shortcode_mostra_produtos( $atts ) {
    /** Our outline will go here
}

Let's take a look at processing attributes. The way shortcode_atts() works is that it will try to match attributes passed to the shortcode with attributes in the passed array, left side being the key and the right side being the defaults. So we need to change defaults to line instead - if we want to default to a category, this would be the place:

$atts = shortcode_atts( array(
    'line' => ''
), $atts );

IF the user adds a attribute to the shortcode line="test" then our array index line will hold test:

echo $atts['line']; // Prints 'test'

All other attributes will be ignored unless we add them to the shortcode_atts() array. Finally it's just the WP_Query and printing what you need:

/**
 * Register all shortcodes
 *
 * @return null
 */
function register_shortcodes() {
    add_shortcode( 'produtos', 'shortcode_mostra_produtos' );
}
add_action( 'init', 'register_shortcodes' );

/**
 * Produtos Shortcode Callback
 * 
 * @param Array $atts
 *
 * @return string
 */
function shortcode_mostra_produtos( $atts ) {
    global $wp_query,
        $post;

    $atts = shortcode_atts( array(
        'line' => ''
    ), $atts );

    $loop = new WP_Query( array(
        'posts_per_page'    => 200,
        'post_type'         => 'produtos',
        'orderby'           => 'menu_order title',
        'order'             => 'ASC',
        'tax_query'         => array( array(
            'taxonomy'  => 'linhas',
            'field'     => 'slug',
            'terms'     => array( sanitize_title( $atts['line'] ) )
        ) )
    ) );

    if( ! $loop->have_posts() ) {
        return false;
    }

    while( $loop->have_posts() ) {
        $loop->the_post();
        echo the_title();
    }

    wp_reset_postdata();
}