2015-07-28 2 views
2

J'ai un script bash que j'utilise pour faire une boucle et traiter les résultats d'une requête SQL comme celle-ci.bash: code de retour de la commande d'entrée redirigée

while read field1 field2 field3 field4 
do 
    {...something here...} 
done < <(mysql -h $HOST -u $USER -p"$PASS" $DB << EOF 
{...multi-line select query here...} 
EOF) 

Le problème que je ne sais pas comment résoudre est comment puis-je Refactor ce que je peux obtenir le code de retour, l'erreur et sauter sur la boucle en cas de problème interrogation la base de données?

Edit:

J'ai essayé d'utiliser un tube nommé avec ce qui suit.

mkfifo /tmp/mypipe 
mysql -h $HOST -u $USER -p"$PASS" $DB <<EOF>> /tmp/mypipe 
    {...multi-line select query here...} 
EOF 
echo $? 
{...loop here...} 

Cela ne semble pas fonctionner parce que la commande MySQL est assis et attend le tuyau à lire avant de continuer. Donc, à moins que je n'aie quelque chose à lire, mysql ne sortira pas pour avoir un code de retour.

J'ai essayé de stocker les résultats de la requête dans une variable d'abord avec ce qui suit.

DATADUMP=$(mysql -h $HOST -u $USER -p"$PASS" $DB -e \ 
    'select stuff from place \ 
    join table 1 on record ..... \ 
    ') 

La question que je suis tombé sur c'est la boucle de lecture ne ferait que lire les quatre premiers « mots » de la variable DataDump et ignorerait le reste.

À ce stade, à moins que quelqu'un ne revienne avec une idée géniale, je vais mktemp un fichier temporaire pour contenir les résultats de la requête. J'espérais éviter de constamment lire et écrire sur le disque, mais mon délai approche très rapidement.

+0

Lorsque mysql échoue, obtenez-vous une sortie que la boucle voit? Est-ce que vous êtes seulement intéressé dans le cas où la boucle ne court jamais? Ou pouvez-vous obtenir des données partielles mais la commande échoue-t-elle? Si ce dernier (ou vous voulez le code de retour spécifiquement et pas simplement "il a échoué") alors vous devrez peut-être utiliser un fifo afin que vous puissiez exécuter mysql séparément et écrire dessus, puis en lire plus tard (ou quelque chose comme ça). –

+0

Je dirais alors, juste "sauter" pourrait ne pas être suffisant. Tant que la cohérence est importante et qu'il ne s'agit pas de DDL, faites des transactions. En outre, il peut arriver que bash ne soit pas un meilleur choix pour cela. Comme: combiner des requêtes dans un fichier (avec gestion des transactions si possible), puis exécuter. –

+0

Lorsque mysql échoue, quelle que soit sa sortie, elle est traitée par la boucle. – Jeremy

Répondre

0

Il n'existe aucun moyen pratique de procéder autrement, sauf pour capturer la sortie complète de la commande mysql avant de la traiter. Vous pourriez le capturer dans une variable, si vous pensiez qu'il ne s'agirait pas de gigaoctets de données, ou dans un fichier temporaire. C'est le seul moyen de garantir qu'aucun résultat partiel n'est traité en cas d'erreur. Si vous saviez que toutes les erreurs ont produit une sortie vide, alors cela serait raisonnablement simple, puisque la boucle while ne s'exécuterait pas du tout. Vous ne seriez pas en mesure de faire la distinction entre une erreur et une recherche vide, mais vous pouvez travailler autour de ce en produisant une indication d'erreur:

got_data=0 
while read field1 field2; do 
    got_data=1 
    # ... 
done < <(mysql ... || printf "%s %d" "ERROR" $?) <<EOF 
    # ... 
EOF 
) 
if ((!got_data)); then 
    if [[ $field1 == "ERROR" ]]; then 
    # error code is in $field2 
    else 
    # query returned no result 
fi 

Cependant, la prémisse est susceptible d'être faux. En particulier, une défaillance du réseau au milieu du retour de la requête produira probablement à la fois une sortie et une indication d'erreur. Et dans ce cas, le code ci-dessus traiterait le retour partiel.

Si cela ne vous dérange pas de traiter un résultat partiel, tant que l'erreur est finalement détectée, vous pouvez utiliser une simple variation sur le code ci-dessus. Le code garantit qu'une sortie infructueuse de mysql produira éventuellement une ligne qui commence par le jeton ERROR. (Je ne sais pas si mysql garantit la sortie d'un retour à la ligne si la transmission réseau est interrompue.Vous devez jouer à des jeux pour garantir que la ligne d'erreur générée par printf apparaît toujours sur une ligne.)

Il y a une petite astuce dans ce qui précède: La ligne d'erreur (ERROR 3, par exemple) est sortie avec printfsans nouvelle ligne de fin. L'absence du retour à la ligne précédent entraînera la sortie de read avec un code d'échec, même s'il divisera la ligne avec succès en les variables field1 et field2.Cela rend inutile la tentative de distinguer l'indication d'erreur des données normales à l'intérieur de la boucle while, bien que vous ayez besoin d'une indication claire pour le test après la boucle while.