【问题标题】:Bash - Escaping single quotesBash - 转义单引号
【发布时间】:2014-04-29 23:49:34
【问题描述】:

当给定特定 ID、姓氏和名字时,我有一个搜索重复 ID 的数据库脚本。这是它的肉和土豆:

PSQL="psql -p $PGPORT -h $DBHOST -d $DB -tAc "

DUP_ID=$($PSQL "SELECT id FROM inmate WHERE id NOT SIMILAR TO '(0*)${1}' AND lastname ILIKE '${_LNAME}' AND firstname ILIKE '${_FNAME}' LIMIT 1")

效果很好,除非姓氏或名字中包含撇号,例如“O'Neil”。我试图逃避任何 'with \' 的实例,但还没有成功。我花了一整天的时间搜索论坛,并自己尝试了不同的变体,但仍然不会在每个 ' 前面添加 \。

这是我目前得到的:

local _LNAME=`echo "${2}" | sed "s/'/\\\'/g"`
local _FNAME=`echo "${3}" | sed "s/'/\\\'/g"`
echo -e $_LNAME
echo -e $_FNAME

# Output

O'Neil
Robert

一如既往,提前致谢!

【问题讨论】:

  • echo | sed 是怎么回事? Bash 具有用于执行字符串操作的内置参数扩展运算符;例如,您可以运行:in="'"; out="\\'"; escaped_lname=${lname//$in/$out},这将比尝试使用 sed 玩游戏更快、更高效。
  • ...另外,请注意,全大写是环境变量和内置函数的惯例。脚本的本地变量应至少包含一个小写字符,以避免与这些类发生命名空间冲突。
  • ...另外,echo -e 是(如 echo -n)非 POSIX 且通常已弃用; printf 对于echo 的所有非常简单的用法都是首选。如果您想以人类可读的方式显示变量的内容,printf '%q\n' "$_lname" 将是一个更好的习惯——它甚至可以以可以显示的格式显示换行符、回车符和其他不可打印的字符重新进入外壳。

标签: bash escaping psql


【解决方案1】:
QUERY=(
  SELECT id FROM inmate WHERE
  id NOT SIMILAR TO "'(0*)$1'" AND
  lastname ILIKE "'$_LNAME'" AND
  firstname ILIKE "'$_FNAME'" LIMIT 1
)
psql -p $PGPORT -h $DBHOST -d $DB -tAc "${QUERY[*]}"

【讨论】:

  • 整洁,是使用"${array[*]}" 而不是"${array[@]}" 的少数正确方法之一。
  • @JonathanLeffler 好吧,我总是尽可能使用*,它“更简单”,但大多数人不理解我认为的区别
  • 您可以通过使用${_LNAME//\'/''} 将名称中的任何单引号展开成双引号来防止Little Bobby Tables。有一天,我会弄清楚为什么你需要在搜索部分而不是替换部分中使用反斜杠。
  • @StevenPenny,“更简单”?我不太确定将 $IFS 的第一个字符放在任何地方是否完全是一种简单模型 - 特别是如果返回多个单词涉及字符串拆分和全局扩展步骤,而不是仅保留原始单词边界第一名。但是,是的,在这个特定的用例中,当目标是一个单词时,这是一件非常好的事情。
【解决方案2】:

这是传递复杂命令的错误方式:

PSQL="psql -p $PGPORT -h $DBHOST -d $DB -tAc "

改为使用数组:

single_quote="'"
escaped_single_quote="\\'"
quoted_fname=${1//$single_quote/$escaped_single_quote}
quoted_lname=${2//$single_quote/$escaped_single_quote}
psql=( psql -p "$PGPORT" -h "$DBHOST" -d "$DB" -tAc )
dup_id=( "${psql[@]}" "SELECT id FROM ... WHERE ... '${quoted_lname}'" )

...然后使用"${dup_id[@]}" 运行您的命令将保护您免受shell 注入错误。它保证可以保护您免受 SQL 注入攻击(执行这些攻击的方法太多,并且数据库在字符集转换方面有太多的特质,因此无法信任简单的基于字符替换的转义在这里针对恶意数据使用),但是,这就是为什么关心正确性或安全性的人们使用支持绑定参数的语言(bash 不是其中的一个成员)来生成 SQL 查询的原因。

另请参阅 BashFAQ #50 和 freenode.org #bash 频道的 wiki 中的 BashWeaknesses 页面——后者明确指出 SQL 生成是不适合 bash 的任务。

【讨论】:

  • 很好的答案,除了你需要通过加倍来转义单引号。
  • @Jeff,嗯? bash 中的'' 与完全没有引号完全相同。试试看:printf '%s\n' ''*'' 打印本地目录中的所有文件名,就像 printf '%s\n' * 所做的那样,而不是打印由文字单引号包围的 *
  • @Jeff, ...如果您指的是正确的 sql 引用而不是 bash 引用,那么 escaped_single_quote="''" 可能更正确 - - 但这意味着问题本身要求的是错误的东西,因为 OP 明确要求如何添加前导反斜杠,而不是如何双引号或(更一般地)为字符串生成正确的 SQL 引用。
猜你喜欢
  • 2017-08-05
  • 2016-07-08
  • 1970-01-01
  • 2011-11-07
  • 1970-01-01
  • 1970-01-01
  • 2017-08-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多