[英]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
虽然这是一个古老的问题,但值得补充的是,这也可以使用条件来处理:
sed -E '/^[0-9]+ +30{8} /, s/^([0-9]+) +([3-9][0-9]{8,}|[0-9]{10.}).*/\1 250000000 XXXX XXXX XXXX/'
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.