使用 sed 替换指定位置处大于指定数字的数字



我需要编写一个脚本来替换所有大于指定数字的数字,该数字位于以下位置。

1499011200 310961583 142550756 313415036 146983209

在这里,如果第二个项的值超过大于 300000000,我正在编写一个脚本。我需要将整行替换为我想要的值,例如

1499011200 250000000 XXXX XXXX XXXX

我希望我已经把我的问题说清楚了。

提前致谢

这可能对你有用(GNU sed):

sed -r '/^S+s+(300000000|[1-2][0-9]{8}|[0-9]{1,8})s/!c change' file

如果300000000或更少,请保留它,否则更改它。

或使用替换:

sed '/^S+s+(300000000|[1-2][0-9]{8}|[0-9]{1,8})s/!s/^(S+s+).*/1250000000 XXXX XXXX XXXX/' file

这是可行的,但并不简单。(≥以 0 结尾的数字比> 容易。

让我们从一个较小的数字开始。

我们如何匹配大于 30 的数字?

  • 大于 30 但小于 40 的 2 位数字,

    b3[1-9]b
    
  • 2 位数字 40 或更大,

    b[4-9][0-9]b
    
  • 数字越多的数字也更大。

    b[1-9][0-9]{2,}b
    

使用交替来匹配所有情况。

b(3[1-9]|[4-9][0-9]|[0-9]{3,})b

300000000 类似,但工作量更大。在这里,我添加了空格以提高可读性,但您需要在sed正则表达式中删除它们。

b ( 30000000[1-9]
| 3000000[1-9][0-9]
| 300000[1-9][0-9]{2}
| 30000[1-9][0-9]{3}
| 3000[1-9][0-9]{4}
| 300[1-9][0-9]{5}
| 30[1-9][0-9]{6}
| 3[1-9][0-9]{7}
| [4-9][0-9]{8}
| [1-9][0-9]{9}
) b

在 awk 中:

$ awk '$2>300000000{for(i=3;i<=NF;i++)$i="XXXX"}1' file
1499011200 310961583 XXXX XXXX XXXX

解释:

$ awk '                 # using awk
$2>300000000 {          # if the second value is greater than ...
for(i=3;i<=NF;i++)  # for each value aftef the second
$i="XXXX"       # replace it with XXXX
}1' file                # output

虽然这是一个古老的问题,但值得补充的是,这也可以使用条件来处理:

  • FreeBSD/MacOS:
    sed -E '/^[0-9]+ +30{8} /! s/^([0-9]+) +([3-9][0-9]{8,}|[0-9]{10,}).*/1 250000000 XXXX XXXX XXXX/'
  • Linux:
    sed -r '/^[0-9]+ +30{8} /! s/^([0-9]+) +([3-9][0-9]{8,}|[0-9]{10,}).*/1 250000000 XXXX XXXX XXXX/'

解释

我们会偷偷摸摸地处理严格的"大于"!

我们在命令前面加上一个条件,告诉sed处理第二个字段中没有300000000 的生产线。这意味着我们不必担心匹配300000001或 300010000 而不是 300000000。如果一行通过此条件,那么(只有这样!)我们将继续替换any number followed by 300000000 or more followed by anything,通过the first number (only), followed by " 250000000 XXXX XXXX XXXX"

换句话说:

如果第二个字段正好是 300000000,则条件意味着不会发生任何事情。否则,如果它小于 300000000,那么它将与正则表达式"查找"部分不匹配,因此再次不会发生任何事情,否则它将进行替换。

开关:

-E/-r告诉sed使用现代正则表达式。这封信在不同版本的 *nix 之间有所不同,所以它可能是别的东西。这是此选项最常见的两个字母。 请参阅man sed以检查系统上需要的内容。

条件:

这很容易。在以下情况下,将处理该行:

  • ^从行的开头开始....
  • [0-9]+ +一些数字>1 的数字字符后跟一些数字>1 的空格(您的第一个字段和列间距)...
    其次:
  • 30{8}3 后跟正好 8 个零,后跟一个空格。我们需要空间,否则它会匹配,例如,300000000500也是如此。
  • /!条件结束后的!表示"仅在满足此条件时才处理命令。

如果一条线符合此条件,那么我们在第二个字段中有一条正好为 300000000 的线,sed将始终保持该线不变。如果没有,它将尝试找到匹配项并替换它。

正则表达式替换命令:

由于上述条件,仅当第二个字段完全是 300000000 时,才会执行此命令。因此,我们可以假设已经检查过,如果第二个字段中没有恰好包含 300000000,请查看替换操作:

  • s查找/替换...
    匹配并替换此表达式(如果在行中找到)(否则不执行任何操作):
  • ^([0-9]+) +找到行首,后跟任意数字>1 位数字,后跟任意数字>1 空格。这是第一个字段的内容。(...)是一个分组,它告诉正则表达式记住它包含的匹配文本部分 - 这将是第一个字段 - 可能会在替换操作中重复使用。(如果匹配成功,我们希望在更改的行中包含第一个字段的值)。这还必须遵循...
  • ([3-9][0-9]{8,}|[0-9]{10,}).*匹配第二个字段,该字段包含 3-9 后跟 8 位数字或任何 9+ 位数字,仅,然后匹配行尾的任何其他内容。请记住,*是"贪婪的"并且尽其所能匹配,所以我们不必明确地说"到行尾",无论如何它都会这样做。我们也不需要匹配第二个字段之后的空格,因为同样,*+是贪婪的,并且会匹配他们所能匹配的所有数字。因此,我们告诉sed匹配任何包含"(行首)(数字)(空格)(数字>= 300000000)(任何内容)"的行,并记住第一个数字。尽管该模式理论上可以匹配并替换确切的值 300000000,但它永远不会,因为我们事先通过条件排除了这种可能性。另请注意,我们需要末尾的.*,因为sed只替换它匹配的内容 - 如果我们省略它,它不会替换行的其余部分,它只会替换它实际匹配的文本 - 第一个和第二个字段 - 这不是我们想要的。
    如果该行与该表达式匹配,则将匹配的文本(将是整行)替换为:
  • 1 250000000 XXXX XXXX XXXX替换字符串中的1是"反向引用"。它的意思是,"将第一个匹配组的内容放在这里"。因此,这告诉sed将整行(因为这是它匹配的内容)替换为第一个字段的内容,后跟一个空格,后跟"250000000 XXXX XXXX XXXX
  • "。

为了完整起见,如果该行可以有前导空格,则该命令将是:

sed -E '/^ *[0-9]+ +30{8} /! s/^( *[0-9]+) +([3-9][0-9]{8,}|[0-9]{10,}).*/1 250000000 XXXX XXXX XXXX/'

(前导空格(如果有的话)位于分组,以便我们在进行替换时保留它们,以示美观。否则他们会迷路)

做。

相关内容

  • 没有找到相关文章