将关键评论转移到答案中。
原始数据
您忘记了双重公式g中第二个命令的修饰符。-e当第一个-e完成时,所有的行仍然在模式空间(sed 中的主要工作区域)中——它们不会变成 5 个单独读取的行。你读了一行;你还在处理它。请注意,您需要使用修改后的模式:
s/\([0-9]\):/\1-/g
结合这些,在 GNU sed(如问题标题中规定)中,您将获得:
sed -e 's/\./\n/g' -e 's/\([0-9]\):/\1-/g' list.tmp
请注意,POSIXsed和其他版本的第一个表达式sed中的换行符替换有不同的规则。-e
考虑使用awk
如果将工具从 更改sed为awk是一种选择,您可以在 中更简单地执行此操作awk,如Ed Morton在评论中所示。由于该解决方案不需要更改以处理修改后的数据,因此它显然具有优势 - 缺点是它不使用sed. 在“现实世界”中,您使用最好的工具来完成这项工作——在这个例子中,就是awk.
扩展数据
使用“扩展”输入,没有方便的单个数字,但您想将每行的第一个冒号更改为破折号,您必须更加努力:
sed -e 's/\./\n/g' \
-e 's/^\([^:]*\):/\1-/' \
-e 's/\(\n[^:]*\):/\1-/g' \
list.tmp
- 第一个
-e不变。
- 第二个在模式空间的开头查找一个非冒号序列,后跟一个冒号,并将其替换为非冒号序列和一个破折号。修饰符在
g这里无关紧要。
- 第三个
-e查找换行符,后跟一系列非冒号,后跟冒号,并将其替换为换行符、非冒号序列和破折号。修饰符在g这里非常相关。
您可以将它们全部展平到一行上,但-e如果最后两个选项被布置在不同的行上,则更容易看到它们之间的相似之处。
您还可以使用该-E选项尝试 ERE(扩展正则表达式),并将两个单独的替换组合为一个:
{
echo "1:apple:fruit.2:banana:fruit.3:cucumber:veggie.4:date:fruit.5:eggplant:veggie."
echo "one:apple:fruit.two:banana:fruit.three:cucumber:veggie.four:date:fruit.five:eggplant:veggie."
} |
sed -E -e 's/\./\
/g' -e 's/((^|\n)[^:]+):/\1-/g'
这会产生:
1-apple:fruit
2-banana:fruit
3-cucumber:veggie
4-date:fruit
5-eggplant:veggie
one-apple:fruit
two-banana:fruit
three-cucumber:veggie
four-date:fruit
five-eggplant:veggie
如果您不想要额外的空行,请删除最后的换行符:
{
echo "1:apple:fruit.2:banana:fruit.3:cucumber:veggie.4:date:fruit.5:eggplant:veggie."
echo "one:apple:fruit.two:banana:fruit.three:cucumber:veggie.four:date:fruit.five:eggplant:veggie."
} |
sed -E -e 's/\./\
/g' -e 's/((^|\n)[^:]+):/\1-/g' -e 's/\n$//'
反斜杠换行符在 GNUsed和 POSIX(包括 BSD 和 macOS)中都能正常工作sed;\n你可以用GNU重新替换它sed。该命令\n的替换部分s///在 BSD (macOS) 中不起作用sed。POSIXsed要求您使用反斜杠来转义替换文本中的文字换行符:
可以通过将 a 代入其中来拆分行<newline>。应用程序应通过在其前面添加一个 来避开<newline>替换中的<backslash>。
GNU sed 更灵活。
此外(根据potong的回答),还有一个 GNU 特定的修饰符m,您可以使用它在一次操作中进行多行匹配。