ubuntuusers.de

BASH / PostgreSQL: psql soll pro Datensatz eine Zeile erzeugen

Status: Gelöst | Ubuntu-Version: Kein Ubuntu
Antworten |

michahe

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 844

Hallo,

meine script für eine Abfrage, die nur einen Datensatz liefert, ist OK:

1
2
3
4
5
#!/bin/bash
strSQL="SELECT COUNT(\"ID\")
FROM \"Schema\".\"Tabelle\";"
Anzahl=$(psql -U "UserName" -d "DbName" --no-align --tuples-only --command="$strSQL")
echo "$Anzahl"

Jetzt möchte ich statt $Anzahl $Liste für mehrere Datensätze, funktioniert auch, aber leider ohne Zeilenumbruch pro Datensatz:

strSQL="SELECT \"ID\",\"Titel\", \"Name\", \"Vorname\"
FROM \"Schema\".\"Tabelle\";"
Liste=$(psql -U "UserName" -d "DbName" --no-align --tuples-only --field-separator="**" --record-separator="\n" --command="$strSQL")
echo "$Liste"

Wie bekomme ich den Zeilentrenner?

TK87

Anmeldungsdatum:
8. Juli 2019

Beiträge: 227

Wohnort: Aachen

Moin,

michahe schrieb:

Wie bekomme ich den Zeilentrenner?

brauchst nur den record-separator ein wenig korrigieren:

1
Liste=$(psql -U "UserName" -d "DbName" --no-align --tuples-only --field-separator="**" --record-separator=$'\n' --command="$strSQL")

Alternativ könntest du natürlich auch ein Array verwenden:

1
2
Liste=($(psql -U "UserName" -d "DbName" --no-align --tuples-only --field-separator="**" --command="$strSQL"))
printf "%s\n" ${Liste[@]}

Gruß Thomas

michahe

(Themenstarter)

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 844

Danke! TK87 schrieb: ...

Alternativ könntest du natürlich auch ein Array verwenden:

1
2
Liste=($(psql -U "UserName" -d "DbName" --no-align --tuples-only --field-separator="**" --command="$strSQL"))
printf "%s\n" ${Liste[@]}

aber: in der letzten Zeile erhalte ich

Dateiende beim Suchen nach »"« erreicht.

TK87

Anmeldungsdatum:
8. Juli 2019

Beiträge: 227

Wohnort: Aachen

Dann hast du irgendwo in deinem Skript Quotes angefangen, die nicht beendet wurden. Das geht aus den beiden Zeilen nicht hervor.

Folgendes funktioniert problemlos:

1
2
3
4
#!/bin/bash
strSQL="SELECT ID,Vorname,Name FROM Schema.Tabelle;"
Liste=($(psql -U "UserName" -d "DbName" --no-align --tuples-only --field-separator="**" --command="$strSQL"))
printf "%s\n" ${Liste[@]}

michahe

(Themenstarter)

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 844

Danke, TK87 schrieb:

Dann hast du irgendwo in deinem Skript Quotes angefangen, die nicht beendet wurden. ...}}}

Habe meinen Fehler gefunden, jetzt läuft es. Aber die Felder (und die Datensätze!) werden zeilenwese ausgegeben, zudem Felder mit Leerzeichen auch in einzelnen Zeilen. So wird aus einem Feld "Dr. med" die Ausgabe

Dr.
med.

Wie

  • bekomme ich eine Zeile je Datensatz?

  • durchlaufe ich diese Zeilen zur Analyse?

  • splitte ich die Zeilen am Feldtrenner '**', um etwas zu ändern?

TK87

Anmeldungsdatum:
8. Juli 2019

Beiträge: 227

Wohnort: Aachen

michahe schrieb:

Aber die Felder (und die Datensätze!) werden zeilenwese ausgegeben

Die einzelnen Zellen der Tabelle? Kann eigentlich nicht sein, wenn du "**" als Trenner verwendest.

zudem Felder mit Leerzeichen auch in einzelnen Zeilen.

Das ist ganz normal. Standardmäßig trennt bash Werte immer bei Leerzeichen, Tabulatoren und Zeilenumbrüchen. Um das zu ändern und die Werte nur bei Zeilenumbrüchen zu trennen, musst du den Internal Field Separator auf "nur Zeilenumbrüche setzen", indem du folgendes in deinem Skript voransetzt (mache ich standardmäßig in jedem Skript):

1
IFS=$'\n'

michahe

(Themenstarter)

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 844

Hmm,

Dein erster Vorschlag ohne Array war:

1
2
strSQL="SELECT ID,Vorname,Name FROM Schema.Tabelle;"
Liste=$(psql -U "UserName" -d "DbName" --no-align --tuples-only --field-separator="**" --record-separator=$'\n' --command="$strSQL")

und liefert zeilenweise:

1**Michaela**Müller
2**Dr. med. Peter**Bauer

Hier müsste ich noch den Zeilenumbruch erkennen und die Zeilen bei den '**' zerlegen, um die Elemente prüfen / bearbeiten zu können ...

Doc_Symbiosis

Avatar von Doc_Symbiosis

Anmeldungsdatum:
11. Oktober 2006

Beiträge: 4439

Wohnort: Göttingen

Wenn Du mit den Daten wirklich arbeiten willst, nimm am besten etwas anderes als Bash. In Python/Perl oder den meisten höheren Programmiersprachen ist es vielleicht etwas aufwendiger, die erste Abfrage hinzubekommen, aber dann mit den Daten weiterzuarbeiten, ist erheblich angenehmer.

michahe

(Themenstarter)

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 844

Ich habe jetzt: michahe schrieb:

1
2
strSQL="SELECT ID,Vorname,Name, PLZ, Ort FROM Schema.Tabelle;"
Liste=$(psql -U "UserName" -d "DbName" --no-align --tuples-only --field-separator="**" --record-separator=$'\n' --command="$strSQL")

und liefert zeilenweise:

1**Michaela**Müller**52072**Aachen
2**Dr. med. Peter**Bauer**10115**Berlin

Hier müsste ich noch den Zeilenumbruch erkennen und die Zeilen bei den '**' zerlegen, um die Elemente prüfen / bearbeiten zu können ...

Das klappt (fast) mit: while read line; do #Mehrzeiligen Variableninhalt zeilenweise zerlegen; Quelle: https://stackoverflow.com/a/11902221 echo "LINE: '${line}'" readarray -d "**" -t arrListe <<< $line # Zeile in Spalten zerlegen; Quelle: https://linuxsimply.com/bash-scripting-tutorial/string/split-string/ echo ${arrListe[0]} echo ${arrFiles[1]} echo ${arrListe[2]} echo ${arrListe[3]} echo ${arrListe[4]} done <<< "$Liste" Allerdings sind die Elemente [1] und [3] leer, [0], [2] und [4] liefern die richtigen Werte. Warum?

@Doc_Symbiosis: Dein Vorschlag ist für mich nicht sinnvoll, da das hier die Ergänzung einer funktionierenden BASH-Anwendung wird ...

Doc_Symbiosis

Avatar von Doc_Symbiosis

Anmeldungsdatum:
11. Oktober 2006

Beiträge: 4439

Wohnort: Göttingen

Hm, good guess: Funktioniert -d bei readarray vielleicht nur für ein Zeichen?

EDIT: In der Tat nimmt -d anscheinend eine Menge von Zeichen als Wert, keinen String. Also setzt Du in deinem Fall effektiv '*' als Delimiter.

TK87

Anmeldungsdatum:
8. Juli 2019

Beiträge: 227

Wohnort: Aachen

na wenn du die Zeilen sowieso zerlegen willst und die einzelnen Werte prüfen willst:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/bash
IFS=$'\n'
strSQL="SELECT ID,Titel,Name,Vorname From Schema.Tabelle"
for LINE in $(psql -U "$USERNAME" -d "DbName" --no-align --tuples-only --field-separator=" **" --command="$strSQL");do
  set -- $(sed 's#\*\*#\n#g' <<<$LINE) # <-- Setzt folgende Variablen:
                                       #   $1 = ID
                                       #   $2 = Titel
                                       #   $3 = Name
                                       #   $4 = Vorname
  # Arbeite hier für die einzelnen Zeilen weiter
  # ...
done

michahe

(Themenstarter)

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 844

Danke @TK87 schrieb:

na wenn du die Zeilen sowieso zerlegen willst und die einzelnen Werte prüfen willst:

Von dieser Lösung verstehe ich gar nichts, deshalb würde ich gerne bei dieser Variante bleiben.

Danke @Doc_Symbiosis schrieb:

EDIT: In der Tat nimmt -d anscheinend eine Menge von Zeichen als Wert, keinen String. Also setzt Du in deinem Fall effektiv '*' als Delimiter.

Meinst Du den Delimter der SQL-Query ODER bei readarray -d "**"?

  • readarray -d "*" (mit einem STern liefert wie vor jedes zweite Element.

  • '*' als Delimter in der SQL-Query ist nicht sinnvoll, da '*' als Teilstring der Feldinhalte vorkommen kann. Ggf. kann ich (wie?) ein nicht druckbares Steuerzeichen verwenden.

Doc_Symbiosis

Avatar von Doc_Symbiosis

Anmeldungsdatum:
11. Oktober 2006

Beiträge: 4439

Wohnort: Göttingen

Ich meinte den Delimiter bei dem readarray.

Die hier

readarray -d "**"

ist also genau das Gleiche wie dieses hier:

readarray -d "*"

Kannst Du vielleicht mit Tab als Separator arbeiten oder kommt Tab auch als Zeichen in den Daten vor?

michahe

(Themenstarter)

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 844

Danke! Doc_Symbiosis schrieb:

Kannst Du vielleicht mit Tab als Separator arbeiten

Ja, TAB wäre gut!. Aber definiere ich das in der SQL-Query ODER bei readarray -d?

Doc_Symbiosis

Avatar von Doc_Symbiosis

Anmeldungsdatum:
11. Oktober 2006

Beiträge: 4439

Wohnort: Göttingen

Naja, Du musst den Delimiter ja bei beiden setzen. Also bei psql musst Du -F $'\t' setzen.

Bei readarray musst Du dann -d $'\t' verwenden.

Antworten |