繁体   English   中英

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

[英]Using sed to replace a number greater than a specified number at a specified position

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

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 的两位数,

     \b3[1-9]\b
  • 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/苹果操作系统:
    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/'

(前导空格,如果有的话,分组内,所以我们在进行替换时保留它们,为了美观。否则它们会丢失)

完毕。

暂无
暂无

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

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