我需要编写一个脚本来替换所有大于指定数字的数字,该数字位于以下位置。
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/'
(前导空格(如果有的话)位于分组内,以便我们在进行替换时保留它们,以示美观。否则他们会迷路)
做。