ubuntuusers.de

BASH: SQL für psql SELECT ... WHERE ...

Status: Gelöst | Ubuntu-Version: Kubuntu 22.04 (Jammy Jellyfish)
Antworten |

michahe

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 857

Hallo, ich habe in der BASH einen SQL-Befehl zur Erzeugung einer Liste; die Variable txtAutor wird vom Script durch das Auslesen von Dateinamen erzeugt:

1
2
3
#!bin bash
$ txtAutor="Peter Witz"
$ psql -U "user" -d "SchemaName" --no-align --tuples-only -c "SELECT \"ID-Mus\" FROM \"SchemaName\".\"T TabellenName\" WHERE \"Autor\" = '$txtAutor'";

So weit funktioniert das. Aber es gibt auch:

$ txtAutor="Peter O'Brian"

Dort funktioniert es nicht weil den Apostroph (') doppeln (und quoten?) muss. Wie lautet dafür die korrekte Syntax?

michahe

(Themenstarter)

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 857

Habe eine Lösung:

$$$ psql -U "user" -d "SchemaName" --no-align --tuples-only -c "SELECT \"ID-Mus\" FROM \"SchemaName\".\"T Tabelle\" WHERE \"Autor\" = '$(echo ${txtAutor//\'/\'\'})'"

Gibt es Verbesserungsvorschläge? Danke!

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4694

Wohnort: Berlin

Funktioniert das hier?

1
psql -U 'user' -d 'SchemaName' --no-align --tuples-only --set "txtAutor=$txtAutor" -c 'SELECT "ID-Mus" FROM "SchemaName"."T TabellenName" WHERE "Autor" = :txtAutor;'

Wobei psql kein sinnvolles Werkzeug für so etwas ist wenn das nicht funktioniert, weil man kein SQL als Zeichenketten zusammenbastelt, schon gar nicht wenn Werte dafür von aussen kommen.

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1274

michahe schrieb:

Gibt es Verbesserungsvorschläge?

Es gibt die bash Funktion "quote", die eventuell weiter helfen kann

$ txtAutor=$(quote "Peter O'Brian")
$ echo $txtAutor
'Peter O'\''Brian'
$ psql -U "user" -d "SchemaName" --no-align --tuples-only -c "SELECT \"ID-Mus\" FROM \"SchemaName\".\"T Tabelle\" WHERE \"Autor\" = $txtAutor"

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13213

Ein anderer Ansatz wäre vielleicht PREPARE zu nutzen.

Doc_Symbiosis

Avatar von Doc_Symbiosis

Anmeldungsdatum:
11. Oktober 2006

Beiträge: 4453

Wohnort: Göttingen

Und viele der Backslashes zum Escapen könntest Du Dir sparen, wenn Du einfach Single-Quotes statt Double-Quotes verwenden würdest, glaube ich zumindest.

Also, ich kenne das gar nicht, dass so viele Double-Quotes in psql verwendet werden, außer die äußeren umschließenden.

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4694

Wohnort: Berlin

@Doc_Symbiosis: Das kann man sich in SQL nicht aussuchen, die beiden bedeuten etwas unterschiedliches. ' sind für Zeichenketten und " sind für Namen damit man da auch Sonderzeichen wie Leerzeichen oder - verwenden kann, und auch SQL-Schlüsselworte. Also mindestens bei ID-Mus und T Tabelle müssen die " sein, sonst ist das syntaktisch falsch. Und es gibt Leute die einfach aus Gewohnheit/zur Sicherheit alle Namen in " einschliessen. Dann kann man zum Beispiel auch sicher sein, das eine neue SQL oder Datenbankversion nicht durch ein neues Schlüsselwort vielleicht vorhandenes SQL ungültig wird.

michahe

(Themenstarter)

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 857

Marc_BlackJack_Rintsch schrieb:

Funktioniert das hier?

1
psql -U 'user' -d 'SchemaName' --no-align --tuples-only --set "txtAutor=$txtAutor" -c 'SELECT "ID-Mus" FROM "SchemaName"."T TabellenName" WHERE "Autor" = :txtAutor;'

Leider nicht: Syntaxfehler bei »:« (Code: :txtAutor)

michahe

(Themenstarter)

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 857

shiro schrieb:

Es gibt die bash Funktion "quote", die eventuell weiter helfen kann

Leider nicht:

$ txtAutor=$(quote "Peter O'Brian")
bash: quote: Kommando nicht gefunden.

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4694

Wohnort: Berlin

quote ist bei mir definiert, frag mich aber nicht wo das her kommt:

$ type quote
quote is a function
quote () 
{ 
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
}

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1274

michahe schrieb:

Leider nicht:

$ txtAutor=$(quote "Peter O'Brian")
bash: quote: Kommando nicht gefunden.

Schau mal nach, ob bei dir das Script

  • $HOME/.config/bash_completion oder

  • /usr/share/bash-completion/bash_completion

ausgeführt wird.

Ein Tip: Schau dir mal an, was

$ bash -x -l -i

ausgibt.

michahe

(Themenstarter)

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 857

Marc_BlackJack_Rintsch schrieb:

quote ist bei mir definiert ...

Hier nicht:

$  type quote
bash: type: quote: Nicht gefunden

shiro schrieb:

Ein Tip: Schau dir mal an, was

$ bash -x -l -i

ausgibt.

ca. 900 Zeilen, darin habe ich nach "completion" gesucht:

++ PROMPT_COMMAND+=('printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/\~}"')
++ [[ -r /usr/share/bash-completion/bash_completion ]]
+ unset TERMCAP
+ unset MANPATH
+ [[ -f /home/meinname/.bashrc ]]
+ . /home/meinname/.bashrc
++ [[ himxBH != *i* ]]
++ '[' -r /usr/share/bash-completion/bash_completion ']'

Schau mal nach, ob bei dir das Script

  • $HOME/.config/bash_completion oder

  • /usr/share/bash-completion/bash_completion

ausgeführt wird.

/usr/share/bash-completion/ existiert, mit 257 Elementen in /usr/share/bash-completion/completions/, aber kein "quote".

Wenn ich die Funktion in mein Skript einbauen möchte, wäre folgender Ansatz korrekt:

FUNC_QuoteApostroph () 
{ 
    local quoted=${1//\'/\'\\\'\'};
    printf "'%s'" "$quoted"
} 

und

$ txtAutor="Peter O'Brian"
$ txtAutor=FUNC_QuoteApostroph(txtAutor)

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1274

++ [[ -r /usr/share/bash-completion/bash_completion ]]

Das sieht so aus, als ob das Script nicht ausgeführt wird, denn es folgt danach kein sourcen (.) des scripts. Ist deinem User das Leserecht für die Datei entzogen? Es sollte eigentlich so aussehen, wie der Aufruf von .bashrc darunter.

Es sollte eigentlich folgendes existieren:

$ ls -l /usr/share/bash-completion/bash_completion
-rw-r--r-- 1 root root 77071 Nov 15  2021 /usr/share/bash-completion/bash_completion
$ grep -A4 -B1 "^quote()" /usr/share/bash-completion/bash_completion
# This function shell-quotes the argument
quote()
{
    local quoted=${1//\'/\'\\\'\'}
    printf "'%s'" "$quoted"
}
$ 
$ txtAutor="Peter O'Brian"
$ txtAutor=FUNC_QuoteApostroph(txtAutor)

Was machst du da? Wenn du "FUNC_QuoteApostroph" als bash Funktion deklarierst, darfst du doch keine Klammern zur Parameter-Übergabe nutzen. Gemäß bash wäre dann korrekter:

$ txtAutor="Peter O'Brian"
$ txtAutor=$(FUNC_QuoteApostroph "$txtAutor")
$ echo $txtAutor
'Peter O'\''Brian'
$ 

michahe

(Themenstarter)

Anmeldungsdatum:
12. Dezember 2013

Beiträge: 857

shiro schrieb:

++ [[ -r /usr/share/bash-completion/bash_completion ]]

Das sieht so aus, als ob das Script nicht ausgeführt wird, denn es folgt danach kein sourcen (.) des scripts. Ist deinem User das Leserecht für die Datei entzogen? Es sollte eigentlich so aussehen, wie der Aufruf von .bashrc darunter.

Es sollte eigentlich folgendes existieren:

$ ls -l /usr/share/bash-completion/bash_completion...
> 

Nein, bei mir schaut es so aus:

 tree /usr/share/bash-completion/
/usr/share/bash-completion/
├── completions
│   ├── adb
│   ├── addpart
│   ├── aria2c
│   ├── blkdiscard
│   ├── blkid
│   ├── blkzone
│   ├── blockdev
│   ├── bluetooth -> tlp
│   ├── bootctl
│   ├── btrfs
│   ├── busctl
│   ├── bwrap
│   ├── cal
│   ├── calf
│   ├── cfdisk
│   ├── chcpu
│   ├── chfn
│   ├── chmem
│   ├── chrt
│   ├── chsh
│   ├── col
│   ├── colcrt
│   ├── colormgr
│   ├── colrm
│   ├── column
│   ├── coredumpctl
│   ├── cpupower
│   ├── ctrlaltdel
│   ├── dbus-send
│   ├── dconf
│   ├── delpart
│   ├── devlink
│   ├── dmesg
│   ├── eject
│   ├── fadvise
│   ├── fallocate
│   ├── fastboot
│   ├── fdisk
│   ├── fincore
│   ├── findfs
│   ├── findmnt
│   ├── firewall-cmd
│   ├── flock
│   ├── fsck
│   ├── fsck.cramfs
│   ├── fsck.minix
│   ├── fsfreeze
│   ├── fstrim
│   ├── fwupdmgr
│   ├── fwupdtool
│   ├── gapplication
│   ├── gdal2tiles.py -> gdalinfo
│   ├── gdal2xyz.py -> gdalinfo
│   ├── gdaladdo -> gdalinfo
│   ├── gdalbuildvrt -> gdalinfo
│   ├── gdal_calc.py -> gdalinfo
│   ├── gdalchksum.py -> gdalinfo
│   ├── gdalcompare.py -> gdalinfo
│   ├── gdal-config -> gdalinfo
│   ├── gdal_contour -> gdalinfo
│   ├── gdal_create -> gdalinfo
│   ├── gdaldem -> gdalinfo
│   ├── gdal_edit.py -> gdalinfo
│   ├── gdalenhance -> gdalinfo
│   ├── gdal_fillnodata.py -> gdalinfo
│   ├── gdal_grid -> gdalinfo
│   ├── gdalident.py -> gdalinfo
│   ├── gdalimport.py -> gdalinfo
│   ├── gdalinfo
│   ├── gdallocationinfo -> gdalinfo
│   ├── gdalmanage -> gdalinfo
│   ├── gdal_merge.py -> gdalinfo
│   ├── gdalmove.py -> gdalinfo
│   ├── gdal_polygonize.py -> gdalinfo
│   ├── gdal_proximity.py -> gdalinfo
│   ├── gdal_rasterize -> gdalinfo
│   ├── gdal_retile.py -> gdalinfo
│   ├── gdal_sieve.py -> gdalinfo
│   ├── gdalsrsinfo -> gdalinfo
│   ├── gdaltindex -> gdalinfo
│   ├── gdaltransform -> gdalinfo
│   ├── gdal_translate -> gdalinfo
│   ├── gdal_viewshed -> gdalinfo
│   ├── gdalwarp -> gdalinfo
│   ├── gdbus
│   ├── getopt
│   ├── gio
│   ├── git
│   ├── gresource
│   ├── grub
│   ├── gsettings
│   ├── gst-inspect-1.0
│   ├── gst-launch-1.0
│   ├── hardlink
│   ├── hexdump
│   ├── homectl
│   ├── hostnamectl
│   ├── hwclock
│   ├── hwloc
│   ├── img2sixel
│   ├── inkscape
│   ├── ionice
│   ├── ipcmk
│   ├── ipcrm
│   ├── ipcs
│   ├── irqtop
│   ├── isosize
│   ├── journalctl
│   ├── kernel-install
│   ├── kmod
│   ├── last
│   ├── lastb -> last
│   ├── ldattach
│   ├── lilv
│   ├── localectl
│   ├── logger
│   ├── loginctl
│   ├── look
│   ├── losetup
│   ├── lsar
│   ├── lsblk
│   ├── lscpu
│   ├── lsinitcpio -> mkinitcpio
│   ├── lsipc
│   ├── lsirq
│   ├── lslocks
│   ├── lslogins
│   ├── lsmem
│   ├── lsns
│   ├── machinectl
│   ├── makepkg -> pacman
│   ├── mbimcli
│   ├── mcookie
│   ├── mesg
│   ├── mkfs
│   ├── mkfs.bfs
│   ├── mkfs.cramfs
│   ├── mkfs.minix
│   ├── mkinitcpio
│   ├── mkswap
│   ├── mmcli
│   ├── more
│   ├── mount
│   ├── mountpoint
│   ├── mpv
│   ├── namei
│   ├── networkctl
│   ├── newgrp
│   ├── nfc -> tlp
│   ├── nmcli
│   ├── nsenter
│   ├── ogr2ogr -> gdalinfo
│   ├── ogrinfo -> gdalinfo
│   ├── ogrlineref -> gdalinfo
│   ├── ogrmerge.py -> gdalinfo
│   ├── ogrtindex -> gdalinfo
│   ├── oomctl
│   ├── openconnect
│   ├── p11-kit
│   ├── pacat -> pactl
│   ├── pacman
│   ├── pacman-key -> pacman
│   ├── pactl
│   ├── padsp -> pactl
│   ├── pamac
│   ├── paplay -> pactl
│   ├── parec -> pactl
│   ├── parecord -> pactl
│   ├── partx
│   ├── patool
│   ├── pg
│   ├── pip
│   ├── pipesz
│   ├── pivot_root
│   ├── poetry
│   ├── portablectl
│   ├── powertop
│   ├── prlimit
│   ├── pulseaudio -> pactl
│   ├── pygmentize
│   ├── qmicli
│   ├── qpdf
│   ├── readprofile
│   ├── rename
│   ├── renice
│   ├── resizepart
│   ├── resolvectl
│   ├── rev
│   ├── rfkill
│   ├── rtcwake
│   ├── runuser -> su
│   ├── script
│   ├── scriptlive
│   ├── scriptreplay
│   ├── setarch
│   ├── setpriv
│   ├── setsid
│   ├── setterm
│   ├── sfdisk
│   ├── snap
│   ├── su
│   ├── swaplabel
│   ├── swapoff
│   ├── swapon
│   ├── systemctl
│   ├── systemd-analyze
│   ├── systemd-cat
│   ├── systemd-cgls
│   ├── systemd-cgtop
│   ├── systemd-cryptenroll
│   ├── systemd-delta
│   ├── systemd-detect-virt
│   ├── systemd-dissect
│   ├── systemd-id128
│   ├── systemd-nspawn
│   ├── systemd-path
│   ├── systemd-resolve
│   ├── systemd-run
│   ├── systemd-sysext
│   ├── taskset
│   ├── tc
│   ├── timedatectl
│   ├── tlp
│   ├── tlp-stat -> tlp
│   ├── tracker3
│   ├── trust
│   ├── tunelp
│   ├── uclampset
│   ├── udevadm
│   ├── udiskie
│   ├── udiskie-info
│   ├── udiskie-mount
│   ├── udiskie-umount
│   ├── udisksctl
│   ├── ufw
│   ├── ul
│   ├── umount
│   ├── unar
│   ├── unshare
│   ├── utmpdump
│   ├── uuidd
│   ├── uuidgen
│   ├── uuidparse
│   ├── waitpid
│   ├── wall
│   ├── wdctl
│   ├── whereis
│   ├── wifi -> tlp
│   ├── wipefs
│   ├── wl-copy
│   ├── wl-paste
│   ├── write
│   ├── wwan -> tlp
│   ├── x264
│   ├── xkbcli
│   ├── yt-dlp
│   └── zramctl
└── helpers
    └── gst

3 directories, 258 files

Wenn du "FUNC_QuoteApostroph" als bash Funktion deklarierst, darfst du doch keine Klammern zur Parameter-Übergabe nutzen. Gemäß bash wäre dann korrekter:

$ txtAutor="Peter O'Brian"
$ txtAutor=$(FUNC_QuoteApostroph "$txtAutor")
$ echo $txtAutor
'Peter O'\''Brian'
$ 

Danke! Ist mein Code zur FUNC_QuoteApostroph wenigstens richtig? Lass uns die bash_completion vergessen, ich würde die FUNC in meinen Code einbauen ...

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1274

Lass uns die bash_completion vergessen, ...

Ich denke, du hast das Paket "bash-completion" nicht installiert, was normalerweise automatisch erfolgt. Aber ok, lassen wir das.

Ist mein Code zur FUNC_QuoteApostroph wenigstens richtig?

Da ich kein "psql" verwende, habe ich mal kurz eine sqlite3 Datenbank erstellt und relevante Daten zum testen eingegeben. Dabei ist mir aufgefallen, dass ein einfaches Verdoppeln des Apostrophs eher zum Ziel führt. Beispiel:

$ FUNC_QuoteApostroph () 
{ 
    local quoted=${1//\'/\'\'};
    printf "'%s'" "$quoted"
} 
$ txtAutor="Peter O'Brian"
$ txtAutor=$(FUNC_QuoteApostroph "$txtAutor")
$ echo $txtAutor
'Peter O''Brian'
$ sqlite3 xdb.db "select * from test where name = $txtAutor;"
2|Peter O'Brian|Mal sehen
$ 
$ # dagegen mit der ursprünglichen "quote" Funktion:
$ txtAutor="Peter O'Brian"
$ txtAutor=$(quote "$txtAutor")
$ echo $txtAutor
'Peter O'\''Brian'
$ sqlite3 xdb.db "select * from test where name = $txtAutor;"
Error: in prepare, unrecognized token: "\" (1)
$ 

Welche Variante bei "psql" zum Ziel führt, solltest du selbst ausprobieren.

PS: Es geht noch etwas einfacher:

$ q(){ printf "'%s'" "${1//\'/\'\'}";}
$ txtAutor="Peter O'Brian"
$ sqlite3 xdb.db "select * from test where name = $(q "$txtAutor");"
2|Peter O'Brian|Mal sehen
$ 
Antworten |