Suppose we start with this string:
echo "1:apple:fruit.2:banana:fruit.3:cucumber:veggie.4:date:fruit.5:eggplant:veggie.">list.tmp
and want to end up with this result:
1-apple:fruit
2-banana:fruit
3-cucumber:veggie
4-date:fruit
5-eggplant:veggie
Why does this work:
sed -e 's/\./\n/g' -i list.tmp
sed -e 's/:/-/' list.tmp
But but not this:
sed -e 's/\./\n/g' -e 's/:/-/' list.tmp
The second command yields this, apparently ignoring the new newlines when looking for the first occurrence of ':' on each line.
1-apple:fruit
2:banana:fruit
3:cucumber:veggie
4:date:fruit
5:eggplant:veggie
With an extended version of the input:
echo "one:apple:fruit.two:banana:fruit.three:cucumber:veggie.four:date:fruit.five:eggplant:veggie.">list.tmp
I want to end up with this result:
one-apple:fruit
two-banana:fruit
three-cucumber:veggie
four-date:fruit
five-eggplant:veggie
Transferring key comment into an answer.
Original data
You forgot the
gmodifier on the second command in the double-eformulation. When the first-ecompletes, all the lines are still in the pattern space (the main working area in sed) — they do not become 5 separately read lines. You read one line; you're still processing it. Mind you, you'll need to use a modified pattern:Combining these, in GNU
sed(as stipulated in the question title), you get:Note that POSIX
sedand other versions ofsedhave different rules about the newline substitution in the first-eexpression.Consider using
awkIf changing tools from
sedtoawkis an option, you can do it more simply inawk, as shown by Ed Morton in a comment. Since that solution doesn't need to change to address the revised data, it clearly has advantages — the disadvantage is that it is not usingsed. In 'the real world', you use the best tool for the job — and in this example, that'sawk.Extended data
With the 'extended' input, where there aren't convenient single digit numbers but you want to change the first colon on each line to a dash, you have to work harder:
-ein unchanged.gmodifier is irrelevant here.-elooks for a newline followed by a sequence of non-colons followed by a colon, and replaces it with the newline, the non-colon sequence and a dash. Thegmodifier is very relevant here.You can flatten that all onto one line, but it is easier to see the similarities between the last two
-eoptions if they're laid out on separate lines.You can also experiment with ERE (extended regular expressions) with the
-Eoption, and group the two separate replacements into one:That yields:
If you don't want the extra blank line, remove the final newline:
The backslash-newline notation works correctly in both GNU
sedand POSIX (including BSD and macOS)sed; you can re-replace that with\nin GNUsed. The\nin the replacement part of thes///command doesn't work in BSD (macOS)sed. POSIXsedrequires that you use a backslash to escape a literal newline in the replacement text:GNU sed is more flexible.
Also (according to potong's answer), there is a GNU-specific modifier
mthat you can use to do the multi-line matching in one operation.