In a Perl script, you have to tell the "always open" file handle STDOUT which encoding to use for writing data.

#!/usr/bin/perl
 
use strict;
use warnings;
 
use Getopt::Long;
use DBI;
 
my %opt = ();
GetOptions(
    \%opt,
    qw/dbname=s dbuser=s dbpass=s/
);
 
foreach my $option (qw/dbname dbuser dbpass/) {
  if (not defined($opt{$option})) {
    die('Error: --'.$option.' must be set'."\n");
  }
}
 
# We tell the Oracle connector which encoding to use. The last part of the
# environment variable NLS_LANG is relevant concerning data
# encoding. AL32UTF8 is what everybody assume to be true UTF-8
$ENV{NLS_LANG} = 'AMERICAN_AMERICA.AL32UTF8';
 
# We have to telle the STDOUT that data will be printed in UTF-8
binmode(STDOUT, ':utf8');
 
my $dbh = DBI->connect(
    'DBI:Oracle:'.$opt{dbname},
    $opt{dbuser},
    $opt{dbpass},
)
    or die "can't connect to database";
 
my $query = 'select string from topic245';
 
my $sth = $dbh->prepare($query);
$sth->execute()
    or die "can't execute input query";
 
while (my ($string) = $sth->fetchrow_array()) {
    # The data is slightly transformed (uppercase) to show that Perl
    # "understands" the characters, it's not only bytes.
    print uc $string, "\n";
}
 
$sth->finish();
$dbh->disconnect();

The Perl script in use:

[pierrick@plegall] ~
$ sqlplus root@TALEND
[...]
Connecté à :
Oracle9i Release 9.2.0.1.0 - Production
JServer Release 9.2.0.1.0 - Production
 
SQL> select * from TOPIC245;
 
STRING
---------
salut
Noël
➊➋➒
éàù€
 
SQL> quit
Déconnecté de Oracle9i Release 9.2.0.1.0 - Production
JServer Release 9.2.0.1.0 - Production
 
[pierrick@plegall] ~
$ oracle_to_stdout-utf8.pl --dbname=TALEND --dbuser=root --dbpass=****
SALUT
NOËL
➊➋➒
ÉÀÙ€