Australian Jack Miller took third after championship leader Fabio Quartararo was hit with a three-second penalty for straying off the track a few laps from the end.
"Everything was so hard: tyre management, keeping cool when Fabio was putting the pressure on me for so many laps," said Oliveira, who rides for KTM.
"I kept it really cool when he overtook me. I saw my chance on the straight and overtook him back. It was the perfect race."
Both Quartararo and Miller led briefly, but both had problems on a warm Catalan afternoon.
Frenchman Quartararo was penalised three seconds for going way off the track on his Yamaha at the chicane four laps from the end.
The rider from Nice also finished the race barechested, after unzipping his jacket, pulling out his chest protector and discarding it.
Quartararo remains top of the rider standings but Zarco, of the Ducati satellite team Pramac, cut the gap to just 17 points.
Miller climbed to third, overtaking his factor Ducati team-mate, Italian Francesco Bagnaia, who was seventh on Sunday.
Spanish title holder Joan Mir (Suzuki), who started 10th on the grid, finished fifth, while multiple world champions Marc Marquez (Honda) and Italian Valentino Rossi (Yamaha-SRT) retired after crashes.
Zarco, who has still to win in the MotoGP class, moved through the pack late in the race but was not quite able to catch the smooth-riding Oliveira.
"The last two laps I tried to catch Miguel," said Zarco. "But he just told me was also controlling well. I was not close enough to try to attack him."
The race was the first this season to allow fans, with a crowd of 24,000, 20 percent of capacity permitted.
After crossing the line, Oliveira raced to the stands to collect a Portuguese flag.
"Thank you to all the fans here everything has been amazing this weekend with the public back in the grandstand and it feels good to be back to normal," said Oliveira.