用sed替换四次

用sed替换四次

我想替换该字符串中的第二个、第三个、第四个和第五个点

2019-03-17T11:32:28.143343Z;1234.5678;901.234;567.89012;3456.78;192.168.0.1

用逗号,得到这个结果:

2019-03-17T11:32:28.143343Z;1234,5678;901,234;567,89012;3456,78;192.168.0.1

第一个逗号和第六个(以及之后的任何逗号)应保持不变。

我找到了这个命令,我可以多次执行该命令(但可能不是最佳实践):

echo "$tmp" | sed 's/\./\,/2'

我怎样才能用一个命令完成这个任务?

答案1

您的数据由六个;分隔字段组成,您希望将字段 2 到 5(不是 1 或 6)中的点替换为逗号。

这是最简单的方法awk

awk -F ';' 'BEGIN { OFS=FS } { for (i=2; i<=5; ++i) gsub("\\.", ",", $i); print }' file

根据给出的示例数据,这会产生

2019-03-17T11:32:28.143343Z;1234,5678;901,234;567,89012;3456,78;192.168.0.1

该代码只是迭代;每个输入行的 - 分隔字段,并调用对循环迭代的各个字段gsub()进行全局搜索和替换(就像使用s/\./,/gy/./,/in所做的那样)。sed

然后打印修改后的行。

-F选项将输入字段分隔符设置为分号,并且我们使用该BEGIN块还将输出字段分隔符设置为相同的值(否则您将获得空格分隔的字段)。


使用sed,你可能会做类似的事情

sed 's/\./,/2; s/\./,/2; s/\./,/2; s/\./,/2' file

即,将第二个点替换四次(第二个点将随着每次替换而改变,因为您替换了它们)。然而,这假设每个字段内的值的数量保持静态。

为了解决这个问题,如果您在某个字段中有两个以上的点分隔的内容,您可以这样做

sed 'h; s/^[^;]*;//; s/;[^;]*$//; y/./,/; G;H;x; s/;[^\n]*\n/;/; s/\n.*;/;/' file

简而言之,这些命令的作用是

  1. 将原始行复制到保留空间。
  2. 删除模式空间中的第一个和最后一个字段。
  3. 将模式空间中的所有点改为逗号(这是命令y)。现在所有应该改为逗号的点都已更改。现在我们必须从模式空间中的中间位和保留空间中的原始数据重新组合该行。
  4. 使(与G;H;x)模式空间包含

    1. 原始字符串,后跟换行符,
    2. 修改后的中间位,后跟换行符
    3. 又是原来的字符串。
  5. 所以现在模式空间包含三行。删除除第一行的第一个字段和换行符之外的所有内容,并将删除的位替换为;.

  6. 对最后一行做类似的事情,即删除(现在唯一的)换行符和最后一行之前的所有内容;,并替换为;.

  7. 完毕。

或者您可以只使用awk代码。

答案2

由于其他答案正在对问题中未说明的输入做出假设(例如,它是一堆;分隔的值,或者有确切地六个点),我将提供这个稍微笨拙的答案,它可以满足问题的要求:

sed 's/^\([^.]*\.[^.]*\)\.\([^.]*\)\.\([^.]*\)\.\([^.]*\)\./\1,\2,\3,\4,/'

这将每个输入行分解如下:

  • 捕获组 1:从行首开始,除 .,然后一个 .(行中的第一个),然后是另一个任意长的字符序列,除了 .,
  • A.(该行中的第二个),
  • 捕获组 2:除 .,
  • A.(行中的第三个),
  • 捕获组 3:除 .,
  • A.(行中第四个),
  • 捕获组 4:除 .,
  • A.(行中第五个),
  • 接下来的内容(与正则表达式不匹配,但该行可以比上面更多,因为正则表达式不以 结尾 $)。

并将其替换为

  • 捕获组 1:直到第二个的所有内容 .在该行中(包括第一行),
  • A,(替换第二个.),
  • 捕获组 2:第二组之间的所有内容 .第三个,
  • A,(替换第三个.),
  • 捕获组 3:第三组之间的所有内容 .第四个,
  • A,(替换第四个.),
  • 捕获组 4:第四组之间的所有内容 .第五个,
  • A,(替换第五个.),
  • 第五个之后的内容 .

因此它将第二个、第三个、第四个和第五个点替换为逗号。

  • 这不会对少于五个点的行进行任何更改。
  • 这将使第五个点之后的任意数量的点保持不变。
  • 这将替换第二个、第三个、第四个和第五个点,即使该行中只有五个点(即没有第六个点)。

这是另一种专门针对 GNU sed 的方法:

sed 's/\./\n/6g; s/\./,/2g; s/\n/./g'
  • s/\./\n/6g用换行符替换从第六个点开始的所有点。
  • s/\./,/2g  将以逗号开头的所有点替换为第二个点。但这实际上只是第二个到第五个,因为第一个命令消除了第五个之后的所有点(如果有的话)。
  • s/\n/./g 将所有换行符更改回点。当然,该行中唯一的换行符是最初是点的换行符,因此这只是将它们更改回原来的样子。

因此,如果一条线只有三个点,这将更改第二个和第三个点(即使第四个和第五个点不存在)。

警告:  数字和 a 的组合g 作为s 命令上的标志的行为是POSIX 未指定 并且可能因实现而异。这就是 GNU SED 的工作原理,如文档中所述GNU SED 手册

答案3

另一个带有循环的 sed :

sed ':A;s/\([^.]*\.[^.]*\)\.\(.*;[^;]*$\)/\1,\2/;tA' infile

答案4

您可以使用sed编辑器来解决此问题,如下所示:

$ sed -e '
    y/./\n/
    s/\n\(.*\)\n/.\1./
    y/\n/,/
' input.txt

前提是我们首先将所有点转换为换行符,保证模式空间中不存在字符。然后我们将最后一个和第一个换行符改回点。其余换行符全部转换为逗号。

HTH。

相关内容