首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在文件的每一行中找到一个字符串,然后使用bash替换同一行中的另一个字符串。

在文件的每一行中找到一个字符串,然后使用bash替换同一行中的另一个字符串。
EN

Unix & Linux用户
提问于 2022-05-06 03:13:19
回答 2查看 50关注 0票数 1

这是我的剧本:

代码语言:javascript
复制
#! /bin/bash

# C-band Edit
dqt='"'
str5="polarization=${dqt}2${dqt}"
for x in {3600..4200} do;
    sed -i "/$str5.*$x/s/$x/$((x-600))/" satellites.xml
done

我所要做的就是在所有在str5中都有satellites.xml的行中,用x-600替换为x-600,在3600到4200之间,但是上面的脚本给了我语法错误。

EN

回答 2

Unix & Linux用户

回答已采纳

发布于 2022-05-06 04:00:12

我刚刚想到,您不是指字面字符串x-600,而是“从3600到4200之间的每个值中减去600”。在这种情况下,使用perl,而不是sed:

代码语言:javascript
复制
echo "$str5. foo bar 3200 3964 4155 4200 4255" |
  perl -p -e "if (/$str5/) {s/3[6789]\d\d|4[01]\d\d|4200/A1-600/eg}"
polarization="2". foo bar 3200 3364 3555 3600 4255

这使用perl的/e regex修饰符使右侧(D3-600)成为evaluated表达式D4是一个perl变量,它包含匹配值,因此D5-600意味着从该值中减去600。

如果这是你真正想要的,我会在下面留下我最初的答案。还因为它有一些有用的解释,这些解释仍然与上面的perl答案有一定的关联。

与sed一样,perl有一个就地编辑的-i选项,这样您就可以将其直接应用到satellites.xml文件中。详情请参见man perlrun

代码语言:javascript
复制
perl -i -p -e "if (/$str5/) {s/3[6789]\d\d|4[01]\d\d|4200/A8-600/eg}" satellites.xml

还值得注意的是:在处理XML文件时,您可能应该使用XML解析器。幸运的是,perl有几个可供选择,例如XML::解析器或集合libxml-perl

我没有您实际输入的示例,所以我编写了一个示例来演示哪些内容将被更改,哪些将不会:

代码语言:javascript
复制
str5='polarization="2"'

echo "$str5. foo bar 3500 3964 4155 4200 4255" | 
  sed -e "/$str5/ {s/3[6-9][0-9][0-9]/3-600/g; s/4[01][0-9][0-9]/4-600/g; s/4200/4-600/g}"
polarization="2". foo bar 3500 3-600 4-600 4-600 4255

大致翻译为英文,即“如果当前行包含$str5 (polarization="2"),那么对其应用这三个s///操作”。

备注:

  • 没有必要从3600.4200循环。这将使sed一个运行中发生所有更改,而不是600个运行。
  • 您希望更改3600-4200的值。这意味着您需要3次搜索和替换操作:
    • 一张3600-3999英镑
    • 一张4000-4199英镑
    • 一张正好4200英镑

  • 或者,这可以通过两个s///操作来完成,方法是将最后两个操作合并为一个: sed -e "/$str5/ { s/3/3-600/g;S/4200/4600/g }“。
  • 可能还有许多其他方法来优化regexes,但是您越多地这样做,它们在将来就越难读取和修改。
  • 396441554200发生了变化。35004255不是,它们超出了预期的范围。
  • [0-9]不会像您在某些区域设置中所期望的那样工作(在该区域中还有其他字符)。我不知道具体是哪个地区,但我经常看到它被提到,以至于我知道不能完全依赖[0-9]。如果这影响到您,您可以使用[[:digit:]]而不是[0-9],或者使用perl -p而不是sed (因此您可以使用\d而不是[0-9])。同样适用于范围[6-9],使用[6789]代替。
  • 最后,在$str5变量中放入什么内容时要非常小心。因为它被插入到一个sed命令中,所以很容易破坏sed脚本(例如,如果$str5包含一个/,它将破坏/$str5/匹配)。sed不知道它的脚本部分来自shell变量,它看到的只是它被赋予运行的脚本。另外,通过sed作为正则表达式,整个字符串将是<#>interpreted --这意味着regex将不会被解释为文字字符,除非用\对它们进行转义。除非将.转义为\.,否则它将被解释为“任意字符”而不是文字点。
票数 2
EN

Unix & Linux用户

发布于 2022-05-06 08:59:04

原则上,您的尝试是正确的,您没有在do之前用分号关闭列表,正如frabjous指出的:

代码语言:javascript
复制
for x in {3600..4200}; do

但请注意,这将使您编辑601次文件“就位”,实际上创建和删除新文件的威胁每次你执行。

为了避免你可以

  1. sed一些基本的数字理解,一次完成,这很有趣,但并不是很有用。
  2. 使用可以计算pythonperlawk等数字的工具
  3. 将其减少到只有七个实际的替代品,您可以输入到sed
代码语言:javascript
复制
    #! /bin/bash
    # C-band Edit
    dqt='"'
    str5="polarization=${dqt}2${dqt}"
    sed -Ei "/$str5$x/{"$(for x in {36..41}; do echo -n "s/$x([0-9]{2})/$((x-6))\\1/;"; done)";s/4200/3600/;}" satellites.xml

替换将生成sed脚本

代码语言:javascript
复制
s/36([0-9]{2})/30\1/;s/37([0-9]{2})/31\1/;s/38([0-9]{2})/32\1/;s/39([0-9]{2})/33\1/;s/40([0-9]{2})/34\1/;s/41([0-9]{2})/35\1/;s/4200/3600/
票数 1
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/701591

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档