Isso porque * , + são quantificadores gananciosos, tentarão corresponder o máximo possível
$ echo '/lol/pattern03657/qsd/qsd/pattern0001/qsd/' | sed -E 's/(.+pattern[0-9][0-9]*).+//'
/lol/pattern03657/qsd/qsd/pattern0001
perl tem um quantificador não-ágil adicionando ? a +
$ echo '/lol/pattern03657/qsd/qsd/pattern0001/qsd/' | perl -pe 's/(.+?pattern\d+\/).+//'
/lol/pattern03657/
ou use a opção grep com pcre , se disponível
$ echo '/lol/pattern03657/qsd/qsd/pattern0001/qsd/' | grep -oP '^.+?pattern\d+/'
/lol/pattern03657/
Uma solução alternativa com sed é se você souber onde sua string ocorre. Por ex:
$ echo '/lol/pattern03657/qsd/qsd/pattern0001/qsd/' | sed -E 's|^(/[^/]+/pattern[0-9][0-9]*/).+||'
/lol/pattern03657/
Aqui, a partir do início da linha, um conjunto de /text/ precede a string