Я получил файл alphabet , где есть несколько появления в строке.

$ cat alphabet
a b c d e f g 
h i j k a a l
m n a p q r a
s t u v w a x
y z a k l q z

где

$ cat alphabet | grep -o a | wc -l
7

Теперь, как я могу заменить только первые 3 вхождения a на Z чтобы мой файл выглядел следующим образом

Z b c d e f g 
h i j k Z Z l
m n a p q r a
s t u v w a x
y z a k l q z

4 ответа4

3

Perl на помощь:

perl -pe '$c++ while $c < 3 && s/a/Z/' alphabet
2
awk '{
    for (i=1; i<=NF; i++) 
        if ($i == "a" && n < 3) {
            n++
            $i = "Z"
        }
    print
}' alphabet

Или "однострочник"

awk '{for (i=1;i<=NF;i++) if ($i=="a" && n++<3) $i="Z"; print}' alphabet
2

Здесь, седь путь

sed -E ':a;N;$!ba;s#a#Z#;s#a#Z#;s#a#Z#' alphabet

Поскольку sed обычно работает в строках, любая команда для sed будет действовать только на 1 строку за раз. Чтобы иметь возможность заменить только первые 3 вхождения, нам нужно сначала сделать весь файл одним выделением, для которого мы сделаем 3 замены. В противном случае мы будем делать 3 замены в каждой строке.

  • :a создает ярлык
  • N добавляет следующую строку в пространство шаблонов
  • $! пропускает последний перевод строки
  • ba ветви маркировать

Теперь мы выбрали весь файл и будем работать с этим пространством вместо одной строки за раз, сделав 3 замены "а" на "Z".

Вышеприведенная команда будет работать только на GNU sed, более общей, но немного более уродливой версии, которая должна работать на не-GNU sed:

sed -e ':a' -e 'N' -e '$!ba' -e 's#a#Z#' -e 's#a#Z#' -e 's#a#Z#' alphabet

РЕДАКТИРОВАТЬ: Как предлагается в комментариях, добавление версии, которая использует команду g, чтобы сначала заменить все вхождения «a» на «Z», а затем заменить все вхождения «Z» после 3-го на «a» снова, что фактически приводит к замене только первые 3 вхождения «а». Таким образом, вы можете изменить последний номер, чтобы отразить количество замен, которые вам нужны.

sed -e ':a;N;$!ba;s#a#Z#g;s#Z#a#g4' alphabet

1

awk решение , которое было выложено предполагает , что все вхождения отдельные слова.  Хотя это верно для данных примера , оно не указано как истинное для реальных данных.  Следующее решение a больше соответствует духу awk решения, которое было опубликовано:

awk '{ while (changes < 3  &&  sub("a", "Z") > 0) changes++; print }' alphabet

Это заменяет (суб) stitutes вхождения с a , пока счетчик Z не достигнет 3.  Конечно, чтобы действительно изменить файл, вам нужно будет сделать что-то вроде

awk '{while (c < 3 && sub("a","Z")>0) c++; print}' alphabet > t && cp t alphabet && rm t

где t это временный файл.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .