通过Bash Scripting转义MYSQL命令行

时间:2010-12-08 00:31:03

标签: mysql bash ssh escaping sh

PHP有mysql_real_escape_string()来正确转义可能导致问题的任何字符。模仿BASH的这种功能的最佳方法是什么?

无论如何使用bash做准备好的mysql语句?这似乎是最好的方式。

我的大部分变量都不会(不应该)包含特殊字符,但是我会为用户提供完全的密码自由。它可能包含“和”之类的字符。

我可能正在做多个SQL语句,所以我想创建一个接受参数然后运行语句的脚本。这就是我到目前为止所做的:

doSQL.sh:

#!/bin/sh

SQLUSER="root"
SQLPASS="passwor339c"
SQLHOST="localhost"

SQL="$1"
SQLDB="$2"


if [ -z "$SQL" ]; then echo "ERROR: SQL not defined"; exit 1; fi
if [ -z "$SQLDB" ]; then SQLDB="records"; fi

echo "$SQL" | mysql -u$SQLUSER -p$SQLPASS -h$SQLHOST $SQLDB

以及使用所述命令的示例:

example.sh:

PASSWORD=$1
doSQL "INSERT INTO active_records (password) VALUES ('$PASSWORD')"

如果密码密码中包含单引号,显然会失败。

8 个答案:

答案 0 :(得分:11)

在Bash中,printf可以为您进行转义:

$ a=''\''"\;:#[]{}()|&^$@!?, .<>abc123'
$ printf -v var "%q" "$a"
$ echo "$var"
\'\"\\\;:#\[\]\{\}\(\)\|\&\^\$@\!\?\,\ .\<\>abc123

我会留给你判断这是否足够激进。

答案 1 :(得分:4)

这似乎是使用错误工具的经典案例。

你前面有一个很多的工作来实现bash中mysql_real_escape_string()完成的转义。请注意,mysql_real_escape_string()实际上将转义委托给MySQL库,该库考虑了连接和数据库字符集。它被称为“真实”,因为它的前身mysql_escape_string()没有考虑字符集,并且可能被欺骗注入SQL。

我建议使用具有MySQL库的脚本语言,例如Ruby,Python或PHP。

如果您坚持使用bash,请使用MySQL Prepared Statements语法。

答案 2 :(得分:2)

mysql_real_escape_string()当然只转义要引用的单个字符串文字,而不是整个语句。您需要明确字符串在语句中的用途。根据{{​​3}}上的MySQL手册部分,要插入字符串字段,您只需要转义单引号和双引号,反斜杠和NUL。但是,bash字符串不能包含NUL,因此以下内容应该足够了:

#escape for MySQL single string
PASSWORD=${PASSWORD//\\/\\\\}
PASSWORD=${PASSWORD//\'/\\\'}
PASSWORD=${PASSWORD//\"/\\\"}

如果您在LIKE之后使用字符串,您可能还想要转义%_

准备好的陈述是另一种可能性。并确保您不要在bash中使用echo -e

另见string literals

答案 3 :(得分:1)

无论您使用什么引号,都不能逃脱以下结构:

PASSWORD=$1
doSQL "INSERT INTO active_records (password) VALUES (FROM_BASE64('$(echo -n $PASSWORD|base64)'))"

答案 4 :(得分:0)

这将逃避撇号

a=$(echo "$1" | sed s/"'"/"\\\'"/g)

请注意,虽然mysql_real_escape_string也会转义\ x00,\ n,\ r \ n,\,“和\ x1a。请确保为了完全安全而逃避这些。

要逃脱\ x00,例如:

a=$(echo "$1" | sed s/"\x00"/"\\\'"/g)

稍微努力一下,你可以使用一个sed命令来逃避这些。

答案 5 :(得分:0)

当然,为什么不只使用真实的东西呢?

  

任意位置的脚本,例如
  〜/ scripts / mysqli_real_escape.php

#!/bin/php
<?php

$std_input_data = '';
$mysqli             = new mysqli('localhost', 'username', 'pass', 'database_name');

if( ftell(STDIN) !== false  )       $std_input_data = stream_get_contents(STDIN);
if( empty($std_input_data)  )       exit('No input piped in');
if( mysqli_connect_errno( ) )       exit('Could not connect to database');

fwrite  (   STDOUT, 
            $mysqli->real_escape_string($std_input_data) 
        );

exit(0);

?>
  

接下来,从bash终端运行:

chmod +x ~/script/mysqli_real_escape.php`
ln -s ~/script/mysqli_real_escape.php /usr/bin/mysqli_real_escape
  

全部准备好!现在,您可以在bash脚本中使用mysqli_real_escape

#!/bin/bash
MyString="stringW@#)*special characters"
MyString="$(printf "$MyString" | mysqli_real_escape )"

注意:据我了解,使用"$(cmd ..."$var")"的命令替换比使用反引号更可取。但是,由于不需要进一步的嵌套,所以两者都应该很好。

进一步注意:在命令替换"$(...)"中,将创建一个新的引用上下文。这就是为什么变量周围的引号不会弄乱字符串的原因。

答案 6 :(得分:0)

这就是我的做法,my-file.txt包含空格,换行和引号:

IFS='' content=$(cat my-file.txt)
mysql <flags> -e "update table set column = $(echo ${content@Q} | cut -c 2-) where something = 123"

答案 7 :(得分:-1)

这将有效:

echo "John O'hara"  | php -R 'echo addslashes($argn);'

将其传递给变量:

name=$(echo "John O'hara"  | php -R 'echo addslashes($argn);')