使用 sed 将“A”替换为“B”或“C”

Ant*_*y D 4 sed random

这应该是直截了当的,但我无法弄清楚。如果我想使用 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。有谁知道如何解决这个问题?

ImH*_*ere 7

可以将字符串的第一个匹配项替换为:

${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)


ste*_*ver 5

不是 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)