我有一个shell变量(我们将调用x),它包含一个带有shell元字符的字符串。例如,我可能
abc "def's" ghi由.
x='abc "def'\''s" ghi'我希望从该字符串构建一个shell命令(存储在文件中,而不是执行)。我有什么选择?
echo "prog $x" >>file # Doesn't work
echo "prog '$x'" >>file # Doesn't work
echo "prog \"$x\"" >>file # Doesn't work当前解决方案使用sed
y=`echo "$x" | sed 's/\([^a-zA-Z0-9._\-\/]\)/\\\\\1/g'`
echo "prog $y" >>file产出如下(尽管同等产出也是可以接受的):
prog abc\ \ \"def\'s\"\ \ ghi问题是,需要这样做的地方越来越多。有人有更好的解决方案吗?
备注:
sh (相对于bash)和任何sh可能合理别名的东西(例如,在sh仿真模式下的bash )。perl的使用是不可接受的,但其他unix工具的使用可能随处可见。发布于 2016-09-06 06:42:49
下面的解决方案将适用于Bourne可以处理的所有输入字符串(包括换行符),在大多数系统上不使用外部命令,并且可移植到所有现代的类似Bourne的shell :放入此esceval函数的每个参数都分别正确地转义/引用。(我把它命名为esceval,意思是“逃逸评估”,以防您有疑问。)
esceval()
{
case $# in 0) return 0; esac
while :
do
printf "'"
unescaped=$1
while :
do
case $unescaped in
*\'*)
printf %s "${unescaped%%\'*}""'\''"
unescaped=${unescaped#*\'}
;;
*)
printf %s "$unescaped"
break
;;
esac
done
shift
case $# in 0) break; esac
printf "' "
done
printf "'\n"
}以上对我的保证作了更多迂腐的阐述:
${foo#bar}和${foo%%bar}替换(除非您正在获取Solaris 10的/bin/sh或类似的古物,否则您需要关注的所有shell)。printf不是shell中的内置程序( printf仅作为外部命令可用是相当少见的,而sed几乎总是外部命令,而且我已经看到了更多的精简系统,这些系统有printf,但没有sed,如果这很重要的话)。注意:此处发布的版本将一个变量泄漏到全局命名空间(unescaped)中,但您可以通过声明local unescaped (如果您的shell支持该变量)或在子shell中包装函数体(括号--它们甚至可以替换花括号)来轻松地修复这个问题,尽管如果您使用该路径,这一点在视觉上并不明显,而且大多数shell都会为子shell进行分叉处理)。
另一方面,如果您确实需要支持没有这些变量子字符串替换的系统,那么您可以使用sed,但是您需要小心地正确地转义字符串中的换行符这样的棘手的事情:
esceval()
{
case $# in 0) return 0; esac
while :
do
printf "'"
printf %s "$1" | sed "s/'/'\\\\''/g"
shift
case $# in 0) break; esac
printf "' "
done
printf "'\n"
}关于尾随换行符的最后注意事项:您应该注意到Bourne shells从命令替换中剥离了尾行(大多数行都带尾换行符,少数shell只带1行)。换句话说,对此感到厌倦:
# Literal strings work fine:
esceval 'foo
'
# Quoted variable substitution also works fine:
ln='
'
esceval "foo$ln$ln$ln$ln"
# Breaks - newlines never make it into `esceval`:
esceval "`printf 'foo\n\n\n\n'`"还有我做的这个怪物,它将在前两个版本之间进行选择,这取决于您的shell是否有能力支持必要的变量替换语法(但是,它看起来很糟糕,因为只有shell的版本必须在一个eval-ed字符串中,这样才能防止不兼容的shell在他们看到它的时候崩溃):https://github.com/mentalisttraceur/esceval/blob/master/sh/esceval.sh。
发布于 2012-11-13 01:35:33
sh具有功能。
# to_shell_lit() - Creates a shell literal
# Usage: printf '%s\n' "...$( quote "..." )..."
to_shell_lit() {
printf \'
printf %s "$1" | sed "s/'/'\\\\''/g"
printf \'
}测试:
$ x='abc "def'\''s" ghi'
$ printf '%s\n' "$x"
abc "def's" ghi
$ printf '%s\n' "prog `to_shell_lit "$x"`"
prog 'abc "def'\''s" ghi'
$ printf '%s\n' "prog $( to_shell_lit "`pwd`" )"
prog '/home/ikegami/foo bar'$ printf '%s\n' "$( to_shell_lit "a'b" )"
'a'\''b'
$ printf '%s\n' "$( to_shell_lit '-n' )"
'-n'
$ printf '%s\n' "$( to_shell_lit '\\' )"
'\\'
$ printf '%s\n' "$( to_shell_lit 'foo
bar' )"
'foo
bar'采用多个参数的版本:
# to_shell_lit() - Creates a shell literal
# Usage: printf '%s\n' "$( to_shell_lit "..." "..." "..." )"
to_shell_lit() {
local prefix=''
local p
for p in "$@" ; do
printf "$prefix"\'
printf %s "$p" | sed "s/'/'\\\\''/g"
printf \'
prefix=' '
done
}https://stackoverflow.com/questions/13354247
复制相似问题