【问题标题】:Escape SQL parameters in shell pipeline在 shell 管道中转义 SQL 参数
【发布时间】:2014-01-24 13:01:18
【问题描述】:

我的 shell 脚本中有这个

./osmfilter austria-latest.osm --keep="$key=$value" |
./osmconvert - --all-to-nodes --csv="@id @lat @lon @timestamp $key name" --csv-headline |
awk -F "\t" '{if($5 != "" && $6 != "") print "INSERT INTO nodes (name, timestamp, lat, lon, cid) VALUES (\"",$6,"\",\"",$4,"\",",$2,",",$3,","'$cid'");"}' 
> $value.sql
sed -i '1d' $value.sql

现在一行输出通常是这样的:

INSERT INTO nodes (name, timestamp, lat, lon, cid) VALUES (" OMV "," 2013-06-21T19:46:57Z ", 48.2160931 , 14.2793397 ,2);

但如果名称中有 " 或 ' 则 SQL 导入将失败:

INSERT INTO nodes (name, timestamp, lat, lon, cid) VALUES (" "Landkauf" Bund "," 2014-01-04T10:42:33Z ", 46.7899638 , 15.8526000 ,2);

我可以告诉 awk 转义所有 " 内部例如 $6 输出吗? 不必是awk

【问题讨论】:

    标签: sql shell sed awk escaping


    【解决方案1】:

    您可以使用以下命令转义所有"

    awk '{gsub("\"", "\\\"", $6)}
    

    示例

    $ echo '"Landkauf" Bund' | awk '{gsub("\"", "\\\"")}1'
    \"Landkauf\" Bund
    

    大家一起

    你正在使用

    awk -F "\t" '{if($5 != "" && $6 != "") print "INSERT INTO nodes (name, timestamp, lat, lon, cid) VALUES (\"",$6,"\",\"",$4,"\",",$2,",",$3,","'$cid'");"}' 
    

    但可以重新格式化为:

    awk -F "\t" '$5 && $6 {gsub("\"", "\\\"", $6); printf "INSERT INTO nodes (name, timestamp, lat, lon, cid) VALUES (\"%s\", \"%s\", \"%s\", \"%s\", \"%s\");\n", $6, $4, $2, $3, cid}' cid=$cid
    

    因为:

    • if($5 != "" && $6 != "") 等价于 $5 && $6
    • printf 可以让您更好地控制打印内容。
    • $cid 你不能使用这样的 bash 变量。您必须使用 cid 并在我的示例中使用 cid=$cid

    【讨论】:

    • 就这样吗? awk -F "\t" '{if($5 != "" && $6 != "") print "INSERT INTO 节点(名称、时间戳、lat、lon、cid)VALUES (\"",gsub("\" ", "\\\"", $6),"\",\"",$4,"\",",$2,",",$3,","'$cid'");"}'
    • @user638058 查看更新后的答案和进一步的解释。
    【解决方案2】:

    您可以为此使用 xxd 和 sed。大多数实用程序都很难使用引号和斜杠等特殊字符,因此将 ' 替换为 \' 会导致代码不可读。以下命令将您的整个输入转换为十六进制 ascii,每行一个十六进制字符。 sed 然后修改十六进制值而不用担心特殊字符。然后将数据翻译回文本。

    xxd -ps -c 1 input.txt | sed -e 's/22/5c22/g' -e 's/27/5c27/g' | xxd -r -p
    

    解释:

    • xxd -ps -c 1 将输入文件转换为 ascii 的十六进制代码,每行一个字符
    • 's/22/5c22/g' 将“翻译成\”
    • 's/27/5c27/g' 将 ' 转换为 \'
    • xxd -r -p 将十六进制恢复为文本字符并恢复文件

    【讨论】:

    • +1.xxd,不知道我有那个。消除一整类问题!但这真的解决了OP吗?你需要像|xxd -r -p > input.txt.fix && mv -f input.txt.fix input.txt这样在最后重定向吗?
    猜你喜欢
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 2014-05-23
    • 1970-01-01
    • 2014-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多