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
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