Wie erfasse ich eine MySQL-Ergebnismenge in einem Bash-Array?


12

Ich verwende die Bash-Shell unter CentOS 7. Ich möchte eine MySQL-Abfrage über ein Shell-Skript ausführen und jede Ergebniszeile durchlaufen. Wenn 4 Zeilen zurückgegeben würden, dachte ich, ich könnte die vier Zeilen in einem Array wie folgt erfassen:

query="select p.id, p.ebook_id, es.id FROM ...";
echo "$query" > /tmp/query.sql
mysql -u user --password=pass db_id < /tmp/query.sql > /tmp/query.csv

linesIN=`cat /tmp/query.csv | sed 's/\t/,/g'`
arraylength=${#linesIN[@]}
echo $arraylength

$arraylengthWird jedoch immer ausgegeben 1, obwohl mehrere Ergebniszeilen zurückgegeben werden. Wie kann ich das oben Gesagte ändern, um ein Array von Ergebnissen korrekt zu erstellen, wobei jedes Element im Array eine Zeile aus der Ergebnismenge darstellt?


Gibt es einen bestimmten Grund, den Sie nicht --batchfür Ihren mysqlAufruf verwenden? Dafür ist es da.
DopeGhoti

Mein Rat ist, einfach keine Bash zu verwenden. Verwenden Sie eine geeignete Skriptsprache.
Alexander - Reinstate Monica

Antworten:


13

Mit der --batchOption , mysqlsollte auf einer Linie das Ergebnis ein Datensatz ausgegeben und Spalten durch Tabulatoren getrennt. Sie können die Zeilen zu einem Array mit Bashsmapfile und Prozessersetzung oder Befehlsersetzung und Arrayzuweisung lesen :

mapfile results  < <( mysql --batch ... < query.sql )

oder

set -f        # disable globbing
IFS=$'\n'     # set field separator to NL (only)
results=( $(mysql --batch ... ) )

(Beachten Sie, dass danach IFSÄnderungen und Globbing deaktiviert bleiben.)

Wenn Sie dann die Spalten einer Zeile in einige Variablen aufteilen möchten:

IFS=$'\t' read -r col1 col2 col2 ... <<< "${results[0]}"

Ihre Aufgabe

linesIN=`cat /tmp/query.csv | sed 's/\t/,/g'`

ist keine Array-Zuweisung (es fehlt die Klammer). Es wird lediglich die Ausgabe der Befehlssubstitution einer regulären Zeichenfolgenvariablen zugewiesen. (Alle Zeilenumbrüche werden dort eingebettet, es handelt sich jedoch weiterhin um eine einzelne Zeichenfolge.) Funktioniert ${#linesIN[@]}weiterhin, da in Bash / ksh Einzelelement-Arrays und Skalarvariablen gleich funktionieren.


Es gibt also keine Möglichkeit, dies mit 2+ Zeilen zu tun, die von MySQL zurückgegeben werden?
Ken Ingram

5

Eine andere Möglichkeit wäre, die Ausgabe des Befehls an eine while-Schleife weiterzuleiten. Beachten Sie, dass Sie das -N oder die Ergebnisse den Spaltennamen enthalten möchten.

#!/bin/bash
#Script to read output from a mysql command line by line 

mysql -uroot -p example -N -e "select column from table" | while IFS= read -r loop
do
    echo "$loop"
done 

Und wenn Sie nur zählen möchten, führen Sie eine aus select count(columnName)und drucken die Ergebnisse aus.


Wenn man die Ergebnisse woanders verwenden möchte, sind sie außerhalb des nicht zugänglich while.
Ken Ingram

1

Wenn Sie möchten, dass die Anzahl der Zeilen in einer Datei der Anzahl der von der Abfrage zurückgegebenen Zeilen entspricht, zählen Sie einfach die wcAnzahl der Zeilen in der Datei

  arraylength=$( wc -l < /tmp/query.csv)
  echo $arraylength

1
Durch die Verwendung der Umleitung wird wc -l </tmp/query.csvvermieden, dass der Dateiname entfernt werden muss
dave_thompson_085

Vielen Dank für den Vorschlag, ich habe meine Antwort aktualisiert
Arushix
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.