这应该是直截了当的,但我无法弄清楚。如果我想使用 sed 用 C 替换 A 或 B,代码可能是:
$ echo AAXXAAYYBB | sed 's/[AB]/C/g'
CCXXCCYYCC
Run Code Online (Sandbox Code Playgroud)
这导致所有 A 和 B 都转换为 C。
我想要做的是用两个(或可能更多)变量之一替换“A”:
输入:
AAXXAAYYBB
Run Code Online (Sandbox Code Playgroud)
代码:
sed 's/A/[BC]/g'
Run Code Online (Sandbox Code Playgroud)
输出(其中 B 或 C 的替换是随机的):
BCXXCBYYBB
Run Code Online (Sandbox Code Playgroud)
但是此代码只会将 A 更改为...
$ echo AAXXAAYYBB | sed 's/A/[BC]/g'
[BC][BC]XX[BC][BC]YYBB
Run Code Online (Sandbox Code Playgroud)
如果可能的话,我尽量避免在这里使用 PERL。有谁知道如何解决这个问题?
可以将字符串的第一个匹配项替换为:
${str/A/...}
Run Code Online (Sandbox Code Playgroud)
并且,可以使用以下方式生成随机(不是加密安全数字)值:
r=(B C)
${r[RANDOM%2]}
Run Code Online (Sandbox Code Playgroud)
每次r
扩展变量时。
一个完全等效但实现起来要快得多的操作是 AND 来提取值的最后一位: ${r[RANDOM&1]}
所以:
#!/bin/bash
str=AAXXAAYYBB
r=(B C)
while [ "${str%"${str#*A}"}" ]; do # while there is an A to change
str=${str/A/"${r[RANDOM&1]}"}
done
echo "str=$str"
Run Code Online (Sandbox Code Playgroud)
每次调用都会产生一个随机结果。
正点
#!/bin/sh
str=AAXXAAYYZZAAA
while [ "${str%"${str#*A}"}" ]; do # while there is an A.
r=$(od -An -tu1 -N 1 /dev/urandom) # get one random byte
r=$((r&1)) # Is it even or odd?
if [ "$r" -eq 0 ]; then s=B; else s=C;fi # Select B or C
str="${str%%A*}${s}${str#*A}" # Change the string.
done
echo "str=$str"
Run Code Online (Sandbox Code Playgroud)
也许可以使用更简单(但更神秘)的方式读取随机字节,大多数情况下使用更快的内置 printf:
r=$(printf '%d\n' "'$(head -c1 /dev/urandom)")
Run Code Online (Sandbox Code Playgroud)
不是 Sed,而是避免了 Perl:
$ echo AAXXAAYYBB | gawk '
BEGIN{srand()}
{
n = patsplit($0,a,/A/,s);
for(i=1;i<=n;i++) printf("%s%s", rand() < 0.5 ? "B" : "C", s[i]);
print ""
}
'
CBXXCCYYBB
Run Code Online (Sandbox Code Playgroud)