如何让Bash匹配正则表达式,而不是用常量字符串替换值,而是将匹配的值传递给函数,然后从函数的返回值中获取要替换的值。
类似于下面的伪代码,它将[a-d]
的每个匹配替换为相同的字符,但是大写:
function uppercase() { echo ${1^^}; }
string="abcdefgh123cbazyz"
echo ${string//[a-d]/uppercase()}
# output: ABCDef123CBAzyz
我并不特别,任何通常安装在Unix系统上的语言(例如sed
, awk
,甚至bash
内置的有限正则表达式支持)都可以使用。
Bash不能在参数扩展中使用用户定义的函数
要完成你想要的,使用模式匹配和大小写修改:
string="abcdefgh123cbazyz"
echo ${string^^[a-d]}
输出:ABCDefgh123CBAzyz
您可以使用Perl:
perl -lape 's/([a-d])/`uppercase $1`/eg' <<< "$string"
,但这将需要一个可执行的脚本命名为uppercase
。Perl e
(eval)标记在匹配时执行命令
另一种方式是sed:
function uppercase() {
echo ${1^^}
}
export -f uppercase
string="abcdefgh123cbazyz"
echo "echo $(sed 's/([a-d])/$(uppercase 1)/g' <<< "$string")" | sh
使用tr
:
echo abcdefgh123cbazyz | tr '[a-d]' '[A-D]'
或sed
:
echo abcdefgh123cbazyz | sed -r 's|[a-d]|U&|g'
输出:ABCDefgh123CBAzyz
更新 Ruby
:
puts "abcdefgh123cbazyz".gsub(/[a-d]/){ |m| m.upcase }
Callbak with Python
:
import re
s = "abcdefgh123cbazyz"
def repl(m):
return m.upper()
print(re.sub('[[:(.+?):]]', repl, s))
Callback with Perl
:
my $s = "abcdefgh123cbazyz";
$s =~ s/([a-d])/uc($1)/eg;
print "${s}n";
输出:ABCDefgh123CBAzyz
在Perl中,您可以捕获组并将其传递给子例程,使用e
标志:
perl -pe 'sub callback { return uc $_[0] } s/([a-d])/callback $1/eg' <<<"$string"
字符串的输出:
ABCDefgh123CBAzyz
这里我只是提供了我自己的包装器,围绕现有的函数uc
,返回将字母转换为大写。您可以更改子例程的主体来做任何您想做的事情。
下面是您在GNU awk中如何做的(对于split()的第四个参数):
$ cat tst.awk
function uppercase(str) { return toupper(str) }
{
split($0,flds,/[a-d]/,seps)
for (i=1;i in flds; i++) {
printf "%s%s", flds[i], uppercase(seps[i])
}
print ""
}
$ echo "abcdefgh123cbazyz" | gawk -f tst.awk
ABCDefgh123CBAzyz
或使用任意awk:
$ cat tst.awk
function uppercase(str) { return toupper(str) }
{
while ( match($0,/[a-d]/) ) {
printf "%s%s", substr($0,1,RSTART-1), uppercase(substr($0,RSTART,RLENGTH))
$0 = substr($0,RSTART+RLENGTH)
}
print
}
$ echo "abcdefgh123cbazyz" | awk -f tst.awk
ABCDefgh123CBAzyz