好的,一般的解决方案。以下bash函数需要2k
参数;每对都包含一个占位符和一个替换符。由您适当地引用字符串以将它们传递到函数中。如果参数数量为奇数,则将添加一个隐式空参数,这将有效删除最后一个占位符。
无论是占位符,也没有更换可能包含NULL字符,但你可以使用标准C \
作为-escapes例如\0
,如果你需要NUL
S(因此你需要写的\\
,如果你想有一个\
)。
它需要标准的构建工具,该工具应该存在于posix样的系统(lex和cc)上。
replaceholder() {
local dir=$(mktemp -d)
( cd "$dir"
{ printf %s\\n "%option 8bit noyywrap nounput" "%%"
printf '"%s" {fputs("%s", yyout);}\n' "${@//\"/\\\"}"
printf %s\\n "%%" "int main(int argc, char** argv) { return yylex(); }"
} | lex && cc lex.yy.c
) && "$dir"/a.out
rm -fR "$dir"
}
我们假设\
参数中的必要部分已经对此进行了转义,但是需要对双引号进行转义(如果存在)。这就是第二个printf的第二个参数。由于lex
默认操作是ECHO
,我们无需担心。
运行示例(有怀疑的时机;这只是一台便宜的商品笔记本电脑):
$ time echo AB | replaceholder A B B A
BA
real 0m0.128s
user 0m0.106s
sys 0m0.042s
$ time printf %s\\n AB{0000..9999} | replaceholder A B B A > /dev/null
real 0m0.118s
user 0m0.117s
sys 0m0.043s
对于较大的输入,可能需要提供一个优化标志cc
,对于当前的Posix兼容性,最好使用c99
。甚至更雄心勃勃的实现可能会尝试缓存生成的可执行文件,而不是每次都生成它们,但是生成它们并不十分昂贵。
编辑
如果您拥有tcc,则可以避免创建临时目录的麻烦,并享受更快的编译时间,这将对常规大小的输入有所帮助:
treplaceholder () {
tcc -run <(
{
printf %s\\n "%option 8bit noyywrap nounput" "%%"
printf '"%s" {fputs("%s", yyout);}\n' "${@//\"/\\\"}"
printf %s\\n "%%" "int main(int argc, char** argv) { return yylex(); }"
} | lex -t)
}
$ time printf %s\\n AB{0000..9999} | treplaceholder A B B A > /dev/null
real 0m0.039s
user 0m0.041s
sys 0m0.031s
tr AB BA
。