用awk或sed替换和增加字母和数字

时间:2017-02-28 22:44:35

标签: bash perl nginx awk sed

我有一个包含

的字符串
fastcgi_cache_path /var/run/nginx-cache15 levels=1:2 keys_zone=MYSITEP:100m inactive=60m;

此脚本的目标之一是根据先前文件中的值find增加 nginx-cache 两位数。为此,我使用了这段代码:

# Replace cache_path

PREV=$(ls -t /etc/nginx/sites-available | head -n1) #find the previous cache_path number
CACHE=$(grep fastcgi_cache_path $PREV | awk '{print $2}' |cut -d/ -f4) #take the string to change
SUB=$(echo $CACHE |sed "s/nginx-cache[0-9]*[0-9]/&@/g;:a {s/0@/1/g;s/1@/2/g;s/2@/3/g;s/3@/4/g;s/4@/5/g;s/5@/6/g;s/6@/7/g;s/7@/8/g;s/8@/9/g;s/9@/@0/g;t a};s/@/1/g") #increment number
sed -i "s/nginx-cache[0-9]*/$SUB/g" $SITENAME #replace number

也许不那么优雅,但它有效。

另一个目标是增加所有出现的 MYSITE x 的最后一个字母( MYSITEP ,在这种情况下,应该成为MYSITE Q ,在MYSITE P 等之后等,一旦MYSITE Z 将到达,请添加另一个字母,如MYSITE AA , MYSITE AB 等等。

我想的是:

sed -i "s/MYSITEP[A-Z]*/MYSITEGG/g" $SITENAME

但它无法正常工作,因为MYSITEGG是一个静态值,无法使用。 如何计算最后一个字母,将其递增到下一个字母,一旦到达最后一个Z字母,再添加一个字母?

谢谢!

2 个答案:

答案 0 :(得分:4)

Perl的自动增量将按照您描述的方式处理字母和数字

我们也可以整理你的nginx-cache增量,同时我们也会这样做

我假设SITENAME包含要修改的文件的名称?

看起来像这样。我必须将捕获$1分配给普通变量$n以增加它,因为$1是只读的

perl -i -pe 's/nginx-cache\K(\d+)/ ++($n = $1) /e; s/MYSITE\K(\w+)/ ++($n = $1) /e;' $SITENAME

如果您愿意,可以在一次替换中完成,例如

perl -i -pe 's/(?:nginx-cache|MYSITE)\K(\w+)/ ++($n = $1) /ge' $SITENAME

答案 1 :(得分:2)

注意:下面的解决方案是不必要的复杂,因为正如Borodin's helpful answer所示(以及@ stevesliva对此问题的评论), Perl 直接支持按照问题中描述的方式按字母顺序递增字母,方法是将++运算符应用于包含字母(序列)的变量; e.g:

$ perl -E '$letters = "ZZ"; say ++$letters'
AAA

下面的解决方案仍然是一个值得关注的展示,展示了如何从shell中利用Perl的功能,展示了如下技术:

  • 使用s///e确定带表达式的替换字符串。
  • 将字符串拆分为字符数组(split //, "...."
  • 使用ordchr函数来获取char。的代码点,并将(n递增的)代码点转换回char。
  • 字符串复制(x运算符)
  • 数组索引和切片:
    • 获取数组的最后一个元素($chars[-1]
    • 获取除数组的最后一个元素(@chars[0..$#chars-1]
    • 之外的所有元素

perl解决方案(实际上是++可以直接执行的重新实施):

perl -pe 's/\bMYSITE\K([A-Z]+)/
  @chars = split qr(), $1; $chars[-1] eq "Z" ? 
    "A" x (1 + scalar @chars)
    :
    join "", @chars[0..$#chars-1], chr (1 + ord $chars[-1])
/e'  <<'EOF'
...=MYSITEP:...
...=MYSITEZP:...
...=MYSITEZZ:...
EOF

的产率:

...=MYSITEQ:...    # P -> Q
...=MYSITEZQ:...   # ZP -> ZQ
...=MYSITEAAA:...  # ZZ -> AAA

您可以使用perl的{​​{1}}选项将输入文件替换为结果
-i)。

正如Borodin的回答所示,单独使用perl -i -pe '...' "$SITENAME"来解决问题中的所有任务并不困难。

perl函数的s选项允许使用Perl 表达式来确定替换字符串,从而实现复杂的替换:

  • /e引用表达式中的当前$1后缀。

  • MYSITE将后缀拆分为字符数组。

  • @chars = split qr(), $1测试最后一个后缀是否为char。是$chars[-1] eq "Z"

    • 如果是这样的话:后缀会被所有Z替换,并附加A个附加内容 (A)。

    • 否则:最后一个后缀char。被替换为字母中的以下字母
      "A" x (1 + scalar @chars)