web-dev-qa-db-fra.com

Redirection de la sortie d'une application console Oracle dans un canal nommé

Je développe actuellement un plugin pour compiler le code Oracle dans mon éditeur de texte. Les personnes qui ont développé SQL Developer ont récemment ajouté une version en ligne de commande sqlcl. Le problème est qu’il s’agit d’une application Java - et que le lancer (jvm) à chaque fois que je dois effectuer une compilation peut coûter cher - avec certains rapports prenant environ 20 secondes.

Une suggestion que j'ai vue était d'utiliser un canal nommé, qui, si je le fais manuellement, semble bien fonctionner.

Terminal 1:

mkfifo sqlconsole
tail -f sqlconsole | /opt/sqlcl/bin/sql /nolog

Terminal 2:

echo "conn hr/[email protected]/xe" > sqlconsole

Et les instructions sont exécutées avec succès.

Le problème avec ceci cependant, est que dans le terminal 2, je ne reçois aucune des sorties du terminal 1 (ce que je veux).

..

J'ai trouvé ceci article à propos de la lecture de la sortie d'un tube nommé. Cependant, même avec cela, la sortie de sqlcl n'est pas redirigée (et, en écrivant ceci, semble avoir cassé l'entrée )

#!/bin/bash
#consolereader.sh
trap "rm -f sqlconsole" EXIT

if [[ ! -p sqlconsole ]]; then
    echo "pipe does not exist" >&2
    exit 1
fi

while true
do
    if read line < sqlconsole; then
        if [[ "$line" == 'quit' ]]; then
            break
        fi
        echo $line
    fi
done

Terminal 1:

mkfifo sqlconsole
tail -f sqlconsole | /opt/sqlcl/bin/sql /nolog

Terminal 2:

./consolereader.sh &
echo "conn hr/[email protected]/xe" > sqlconsole

Existe-t-il une meilleure approche que je puisse adopter - telle que je puisse laisser sqlcl s'exécuter en arrière-plan et toujours obtenir le résultat dans la session à partir de laquelle j'envoie les commandes?

..

Edit: Essayer la solution de Germar:

setUpPipes.sh (terminal 1):

#!/bin/bash
rm -f sqlconsole
rm -f sqlconsole_out
mkfifo sqlconsole
mkfifo sqlconsole_out
tail -f sqlconsole | /opt/sqlcl/bin/sql /nolog | tee -a sqlconsole_out

compileOracle.sh (terminal 2):

#!/bin/bash
echo "begin.."
tail -f /home/trent/pipedemo/sqlconsole_out &
echo "about to run connection"
echo "conn hr/[email protected]/xe" > /home/trent/pipedemo/sqlconsole
echo "select * from dual" > /home/trent/pipedemo/sqlconsole
echo "disconnect" > /home/trent/pipedemo/sqlconsole
echo "finished"
exit 0

2
trent

Une approche possible consiste à utiliser la commande SPOOL de votre interpréteur SQL.

Alors, démarrez votre pipe nommée comme vous le faisiez déjà:

mkfifo sqlconsole
tail -f sqlconsole | /opt/sqlcl/bin/sql /nolog

Ensuite, créez votre script SQL, mais cette fois en activant serveroutput et en spoulant également dans un fichier spécifié. Dans cet exemple, je vais simplement le faire pour out.txt.

conn hr/[email protected]/xe
SPOOL out.txt    
select * from dual;

set serveroutput on

exec dbms_output.put_line('PROCESS_FINISHED');

SPOOL OFF
disconnect

Ici, j’ai également choisi d’imprimer une chaîne dans le fichier spoulé - PROCESS_FINISHED - afin de signaler la fin du script, le script SQL et le script bash s’exécutant côte à côte, avec le bash script susceptible de se terminer avant la fin du script.

Avec cela, je peux alors créer un script bash (atomRunner.sh) pour l'envoyer au tube nommé:

#!/bin/bash
> out.txt
cat connect.sql > sqlconsole
MAX_TIME=10
scriptStart=$(date -u +"%s")
secondsSince=0

while true; do

    if [[ "${secondsSince}" -ge "${MAX_TIME}" ]] || grep -q "PROCESS_FINISHED" out.txt; then
        break
    fi
    nowDate=$(date -u +"%s")
    secondsSince=$((nowDate-scriptStart))
    sleep 0.1
done

cat out.txt

if [[ "${secondsSince}" -ge "${MAX_TIME}" ]]; then
    echo "Script took longer than expected to complete" >&2
    exit 1
fi

exit 0

Puis en cours d'exécution:

$ ./atomRunner.sh 

SQL> set serveroutput on
SQL> select * from dual;

D
-
X
SQL> exec dbms_output.put_line('PROCESS_FINISHED')
PROCESS_FINISHED

SQL> SPOOL OFF
1
trent