使用sed使用shell脚本替换指定位置中大于指定数字的数字

时间:2017-07-16 07:20:01

标签: bash shell sed

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

1499011200 310961583 142550756 313415036 146983209

如果第二个词的值超过300000000,我正在写一个脚本。我需要将整行替换为我想要的值,如

1499011200 250000000 XXXX XXXX XXXX

我希望我的问题清楚明了。

提前致谢

4 个答案:

答案 0 :(得分:1)

这是可行但不简单。 (≥以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

答案 1 :(得分:1)

这可能适合你(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

答案 2 :(得分:0)

在awk中:

Private Sub ExportFiles()
    Dim lWidthInPixels As Long
    Dim lHeightInPixels As Long

    lWidthInPixels = 1024
    lHeightInPixels = 768

    'pdf
    ActivePresentation.ExportAsFixedFormat "c:\folder1\file1.pdf", _
    ppFixedFormatTypePDF, ppFixedFormatIntentPrint, msoCTrue, ppPrintHandoutHorizontalFirst, _
    ppPrintOutputSlides, msoFalse, , ppPrintAll, , False, False, False, False, False

    'ppt
    Application.ActivePresentation.SaveCopyAs "c:\folder2\file2"

    'png
    Application.ActiveWindow.View.Slide.Export "c:\folder3\file3.png", "png", lWidthInPixels, lHeightInPixels 

End Sub

说明:

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

答案 3 :(得分:0)

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

  • 的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 anythingthe first number (only), followed by " 250000000 XXXX XXXX XXXX"

换句话说:

如果第二个字段正好是300000000,那么条件意味着什么都不会发生。否则,如果它小于300000000,则它将与正则表达式“find”部分不匹配,所以再也不会发生任何事情,否则它将进行替换。

<强>开关

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

<强>条件:

这很容易。如果符合以下条件,将处理该行:

    从行首开始
  • ^ ....
  • [0-9]+ +一些数字&gt; 1的数字字符后跟一些数字&gt; 1个空格(您的第一个字段和列间距)...
    后跟:
  • 30{8} 3接着是8个零后跟一个空格。我们需要它所匹配的空间,例如300000000500。
  • /!条件结束后的!表示“只有在不符合条件时才处理命令。

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

正则表达式替换命令:

由于上述条件,如果第二个字段正好是300000000,则仅执行此命令。因此,我们可以假设已经检查过并查看替换操作,如果它在第二个字段中不包含正好300000000:

  • s执行查找/替换.... 匹配并替换此表达式,如果它在行中找到(否则不执行任何操作):
  • ^([0-9]+) +找到行首,后跟任意数字&gt; 1位数,后跟任意数字&gt; 1个空格。这是第一个字段的内容。 (...)是一个分组,它告诉正则表达式记住它包含的匹配文本的部分 - 这将是第一个字段 - 可能在替换操作中重复使用。 (如果匹配成功,我们希望在更改的行中包含第一个字段的值)。此也必须后跟 ...
  • ([3-9][0-9]{8,}|[0-9]{10,}).*匹配第二个字段,该字段包含EITHER 3-9,后跟8个数字或任何9+位数字,仅适用于该行的末尾。请记住*是“贪婪的”并且尽可能地匹配,所以我们不必明确地说“到行尾”,无论如何它都会这样做。我们也不需要匹配第二个字段后面的空格,因为*+再次贪婪并且会匹配它们可以包含的所有数字。所以我们告诉sed匹配任何包含“(行首)(数字)(空格)(数字&gt; = 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/'

(前导空格,如果有的话, in 分组,以便我们在替换时保留它们,为了好看。否则它们会丢失)

完成。