2016-08-15 4 views
1

Ich mag meine Verbindung und allgemeine Dump-Einstellungen in Variablen setzen und sie dann wie so zu mysqldump füttern:Odd bash Verhalten mit verschachtelten Variablen

# echo mysqldump ${SRC_SRV} ${SRC_SQL_OPT} 
mysqldump -u root -pPass -h host --where="COL > '2016-08-14' AND COL <= '2016-08-15'" --opt --single-transaction --skip-triggers --no-create-db --no-create-info dbase table 

Es gibt meine bash Variablen:

WHERE="COL > '2016-08-14' AND COL <= '2016-08-15'" 
SRC_SQL_OPT="--where=\"${WHERE}\" --opt --single-transaction --skip-triggers --no-create-db --no-create-info ${DB} ${TBL}" 

Beachten Sie, dass, wenn ich echo - alles scheint normal, aber wenn ich versuche, es in bash ausführen, erhalte ich einen Fehler:

mysqldump: Got error: 1049: Unknown database '>' when selecting the database 

Und hier ist der Grund, warum (bash -x):

+ mysqldump -u root -pPass -h host '--where="COL' '>' ''\''2016-08-14'\''' AND COL '<=' ''\''2016-08-15'\''"' --opt --single-transaction --skip-triggers --no-create-db --no-create-info dbase table 

Hinweis: jetzt ein paar zusätzliche einfache Anführungszeichen gibt es rund um die --where Option ... Wie?

Antwort

1

$SRC_SQL_OPT enthält die folgende Zeichenfolge:

--where="COL > '2016-08-14' AND COL <= '2016-08-15'" --opt --single-transaction --skip-triggers --no-create-db --no-create-info dbase table 

Wenn diese Zeichenfolge in mysqldump ${SRC_SRV} ${SRC_SQL_OPT} Erweiterung heftiger Schlag spaltet die Variablen in getrennte Argumente auf seiner internal field separator.

Da standardmäßig der Feldseparator Leerzeichen ist, wird auf $SRC_SQL_OPTaufgeteilt jedes Vorkommen von Leerzeichen-unabhängig davon, ob der Raum innerhalb eines Zitats eingetreten ist oder nicht. Man kann Bash von Splitting Variablen verhindern, indem sie zu zitieren, aber da Sie eigentlich wollen, dass variable Aufteilung anderswo, dann würden Sie entweder brauchen:

  • trennen das, wo ein Teil (wie @Pianosaurus has said), zB:

    WHERE="COL > '2016-08-14' AND COL <= '2016-08-15'" 
    SRC_SQL_OPT="--opt --single-transaction --skip-triggers --no-create-db --no-create-info ${DB} ${TBL}" 
    
    mysqldump $SRC_SRV --where="$WHERE" $SRC_SQL_OPT 
    
  • Verwendung eine andere interne Feldseparator, zB:

    WHERE="COL > '2016-08-14' AND COL <= '2016-08-15'" 
    SRC_SRV="-u;root;-pPass;-h;host" 
    SRC_SQL_OPT="--where=\"$WHERE\";--opt;--single-transaction;--skip-triggers;--no-create-db;--no-create-info;$DB;$TBL" 
    
    IFS=';' mysqldump $SRC_SRV $SRC_SQL_OPT 
    
1

Es gibt einen signifikanten Unterschied zwischen Ihrem ersten Befehl und der Version, die Sie wahrscheinlich mit bash-Variablen verwenden.

Wenn Sie einen Befehl wie den in Ihrem ersten Codeblock ausführen, werden die doppelten Anführungszeichen von bash selbst interpretiert und der Inhalt wird als einzelnes Argument an den Befehl gesendet.

In Ihren Bash-Variablen fügen Sie explizit ein Literal-Zitat ein. Die einzige Möglichkeit, Bash so zu parsen, wie Sie wollen, ist der Befehl eval, da er sowohl Leerzeichen in Anführungszeichen als auch außerhalb von ihnen enthält.

Der sauberste Weg, dies in bash zu tun, ist solche verschachtelten Variablen in Befehlen zu vermeiden. In Ihrem Fall, machen Sie nicht SRC_SQL_OPT vor dem Ausführen des Befehls. Oder zumindest nicht den --where-Teil einschließen.