简体   繁体   English

用命令输出替换字符串,每次都不同

[英]Replace string with output of command, different each time

I have many files and I want to replace the class names with a UUID. 我有很多文件,我想用UUID替换类名。 I figured out this 我想通了

sed -i -r "s/ Class \w(\w|\d)+/ Class C$(python -c 'import uuid;print(uuid.uuid4().hex)')/"

It works fine when the pattern only occurs once in each file. 当模式在每个文件中仅出现一次时,它可以正常工作。 However if the pattern occurs more than once, each occurence is replaced by the same number. 但是,如果模式多次出现,则每次出现都将替换为相同的数字。

Class1.vb Class1.vb

Public Class Class1
    Public ReadOnly Property P As String = "hello"
End Class

Public Class Class2
    Public ReadOnly Property P As String = "hello"
End Class
$ sed -r "s/ Class \w(\w|\d)+/ Class C$(echo $RANDOM)/" Class1.vb
Public Class C27244
        Public ReadOnly Property P As String = "hello"
End Class

Public Class C27244
        Public ReadOnly Property P As String = "hello"
End Class

I expect the two classes to have different names. 我希望两个类具有不同的名称。 How do I fix my script? 如何修复我的脚本?

$ awk '{gsub(/Class [[:alnum:]]+/, "Class C" int(9999*rand()))} 1' Class1.vb
Public Class C2377
    Public ReadOnly Property P As String = "hello"
End Class

Public Class C5854
    Public ReadOnly Property P As String = "hello"
End Class

The above will give you the same random numbers in the same order each time. 上面的代码会每次给您相同顺序的相同随机数。 If you want different random numbers each time you run the program, use: 如果每次运行该程序都需要不同的随机数,请使用:

awk -v s=$RANDOM 'BEGIN{srand(s)} {gsub(/Class [[:alnum:]]+/, "Class C" int(9999*rand()))} 1' Class1.vb

How it works 这个怎么运作

  • gsub(/Class [[:alnum:]]+/, "Class C" int(9999*rand()))

    This looks for occurrences of the regex Class [[:alnum:]]+ and replaces each one with the concatenation of the string Class C and a four-digit random number calculated from int(9999*rand()) . 这将查找正则表达式Class [[:alnum:]]+并用字符串Class C和从int(9999*rand())计算出的四位数随机数的连接替换每个正则表达式。 A new random number is generated for each line. 每行产生一个新的随机数。

  • 1

    This is awk's cryptic shorthand for print-the-current-line. 这是awk的“打印当前行”的隐喻速记。

More as a proof of concept than a serious alternative: a GNU sed solution. GNU sed解决方案更多是作为概念证明而不是严肃的选择。

sed -E -e '/Class \w+/{h;s/.*/bash -c "echo C\\$RANDOM"/;e' \
    -e 'G;s/(.*)\n(.*Class )\w+(.*)/\2\1\3/}' infile

resulting in 导致

Public Class C24276
    Public ReadOnly Property P As String = "hello"
End Class

Public Class C28554
    Public ReadOnly Property P As String = "hello"
End Class

Here is how it works: 下面是它的工作原理:

/Class \w+/ {                           # If the line matches "Class <name>"
    h                                   # Copy pattern space to hold space
    s/.*/bash -c "echo C\\$RANDOM"/     # Write Bash command into pattern space
    e                                   # Replace pattern space with command output
    G                                   # Append hold space to pattern space
    s/(.*)\n(.*Class )\w+(.*)/\2\1\3/   # Swap class name with random number
}

Remarks: 备注:

  • This uses GNU extensions: notably the \\w character class and the e command. 它使用GNU扩展:特别是\\w字符类和e命令。
  • The one-liner version is split into two commands using -e because the e command cannot be followed by anything, or that anything is interpreted as the command. 使用-e将单行代码版本分为两个命令,因为e命令后面不能有任何内容,或者任何内容都可以解释为该命令。
  • The command to be run can't just be echo C$RANDOM because the e command uses sh instead of Bash, and sh might not have $RANDOM (like on Ubuntu, where sh is dash). 要运行的命令不能只是echo C$RANDOM因为e命令使用sh而不是Bash,并且sh可能没有$RANDOM (例如在Ubuntu上, sh是破折号)。
  • Because the command is in double quotes, the $ in $RANDOM has to be escaped, and because sed does a first pass before the shell sees the command, is has to be escaped twice. 由于该命令是在双引号中, $$RANDOM已经被转义,因为做的sed前壳第一遍看的命令,是已被转义两次。 Alternatively, I could have used 或者,我本可以使用

     s/.*/bash -c '\\''echo C$RANDOM'\\''/ 

    to single quote the command, but that's not very readable either. 用单引号将该命令引起来,但这也不是很容易理解。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM