Перевод ключевого комментария в ответ.
Исходные данные
Вы забыли модификатор 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
Обратите внимание, что POSIX sed
и другие версии sed
имеют разные правила замены строки в первом выражении -e
.
Рекомендуется использовать awk
Если вы меняете инструменты с От sed
до awk
- опция, вы можете сделать это более просто в awk
, как показано Ed Morton в комментарии . Поскольку это решение не нуждается в изменении для обращения к пересмотренным данным, оно явно имеет преимущества - недостатком является то, что оно не использует sed
. В «реальном мире» вы используете лучший инструмент для работы - и в этом примере это awk
.
Расширенные данные
С «расширенным» вводом, где нет удобные одиночные числа di git, но вы хотите изменить первое двоеточие в каждой строке на da sh, вам нужно работать усерднее:
sed -e 's/\./\n/g' \
-e 's/^\([^:]*\):/\1-/' \
-e 's/\(\n[^:]*\):/\1-/g' \
list.tmp
- Первый
-e
в неизменном виде. - Второй ищет последовательность не-двоеточий, за которыми следует двоеточие в начале пространства шаблона, и заменяет его на последовательность не-двоеточий и да sh. Модификатор
g
здесь не имеет значения. - Третий
-e
ищет новую строку, за которой следует последовательность не-двоеточий, за которой следует двоеточие, и заменяет ее новой строкой, последовательностью без двоеточия и да sh. Модификатор g
очень важен здесь.
Вы можете выровнять все это на одну строку, но легче увидеть сходство между двумя последними вариантами -e
, если они выложены в отдельных строках.
Вы также можете поэкспериментировать с ERE (расширенными регулярными выражениями) с параметром -E
и сгруппировать две отдельные замены в одну:
{
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$//'
Нотация обратной строки sh с обратным символом работает правильно как в GNU sed
, так и в POSIX (включая BSD и macOS) sed
; вы можете заменить его на \n
в GNU sed
. \n
в замещающей части команды s///
не работает в BSD (macOS) sed
. POSIX sed
требует, чтобы вы использовали обратную косую черту sh для экранирования буквального перехода на новую строку в тексте замены:
Строка может быть разбита путем подстановки <newline>
в Это. Приложение должно экранировать <newline>
в замене, предшествуя ему <backslash>
.
GNU sed является более гибким.
Также (согласно potong ' answer ), существует спецификатор GNU c m
, который можно использовать для выполнения нескольких операций. сопоставление строк за одну операцию.