Хочу заменить только первым вхождением с sed

Если Ваш VM Linux только для разработки, почему Вам нужна настольная среда (или даже X) на нем?

Вы могли выполнить VM без X (и весь багаж, который идет X), и подключение к нему с ssh клиентом (putty.exe). Можно выполнить несколько соединений SSH к VM и/или если у Вас есть Экран GNU или подобный установленный на VM затем, у Вас может быть несколько терминальных сеансов в одном соединении SSH (можно также отсоединить и повторно прикрепить к ним по желанию).

Если Вы хотите упрощенную debian/ubuntu систему затем самый легкий способ добраться, он должен установить систему основы debian в VM и затем установить только пакеты, в которых Вы на самом деле нуждаетесь с Кв. - добираются или способность или что бы то ни было.

Если необходимо выполнить GUI приложения Linux, существуют X-серверы, доступные для MS Windows, включая бесплатные версии (это были много лет, с тех пор как мне было нужно что-либо как это так, я не могу рекомендовать никому) - это позволило бы Вам запускать приложение GUI на Linux и иметь дисплей окна программы на Вашем рабочем столе MS Windows.

28
05.03.2015, 01:32
10 ответов

Если вы используете GNU SED , попробуйте:

sed -e '0,/claudio/ s/claudio/claudia/' nomi

SED не начинает проверять регулярное выражение, которое заканчивается диапазон до после Линия, которая начинает этот диапазон.

Из MAN SED (POSIX MANPAGE, Упорный шахт):

An editing command with two addresses shall select the inclusive  range
from the first pattern space that matches the first address through the
next pattern space that matches the second. 

Использование awk

в awk Работает больше, чем вы ожидали:

$ awk 'NR==1,/claudio/{sub(/claudio/, "claudia")} 1' nomi
claudia
antonio
claudio
michele

Объяснение:

  • NR == 1, / claudio /

    Это диапазон, который начинается с линии 1 и заканчивается первым вхождением Claudio .

  • Sub (/ Claudio /, «Claudia»)

    , в то время как мы находимся в диапазоне, эта замена команда выполняется.

  • 1

    Этот криптичный стенография AWK для печати линии.

25
27.01.2020, 19:39

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

sed -n ':a;N;$bb;ba;:b;s/\(claudi\)o/\1a/;p' file
sed -n '1h;1!H;${g;s/\(claudi\)o/\1a/;p;}' file

С комментарием:

sed -n '                # don't implicitly print input
  :a                    # label "a"
  N                     # append next line to pattern space
  $bb                   # at the last line, goto "b"
  ba                    # goto "a"
  :b                    # label "b"
  s/\(claudi\)o/\1a/    # replace
  p                     # and print
' file
sed -n '                # don't implicitly print input
  1h                    # put line 1 in the hold space
  1!H                   # for subsequent lines, append to hold space
  ${                    # on the last line
    g                     # put the hold space in pattern space
    s/\(claudi\)o/\1a/    # replace
    p                     # print
  }
' file
4
27.01.2020, 19:39

Вы можете использовать awk с флагом, чтобы знать, была ли замена уже сделана. Если нет, продолжить:

$ awk '!f && /claudio/ {$0="claudia"; f=1}1' file
claudia
antonio
claudio
michele
1
27.01.2020, 19:39

На самом деле действительно просто, если вы просто настроите небольшую задержку - нет необходимости дойти до ненадежных расширений:

sed '$H;x;1,/claudio/s/claudio/claudia/;1d' <<\IN
claudio
antonio
claudio
michele
IN

, которые просто дефицит Первая строка до второго и второй на третий и т. Д.

Это печатает:

claudia
antonio
claudio
michele
1
27.01.2020, 19:39

И еще один вариант

sed --in-place=*.bak -e "1 h;1! H;\$! d;$ {g;s/claudio/claudia/;}" -- nomi

Преимущество в том, что он использует двойные кавычки, так что вы можете использовать переменные внутри, т.е.

export chngFrom=claudio
export chngTo=claudia
sed --in-place=*.bak -e "1 h;1! H;\$! d;$ {g;s/${chngFrom}/${chngTo}/;}" -- nomi
1
27.01.2020, 19:39

Это также можно сделать без удерживаемого пространства и без объединения всех строк в пространство шаблона:

sed -n '/claudio/{s/o/a/;bx};p;b;:x;p;n;bx' nomi

Объяснение: Мы пытаемся найти "claudio", и если мы это делаем, мы переходим в небольшой цикл загрузки-печати между : x и bx . В противном случае печатаем и перезапускаем скрипт со следующей строки.

sed -n '      # do not print lines by default
  /claudio/ { # on lines that match "claudio" do ...
    s/o/a/    # replace "o" with "a"
    bx        # goto label x
  }           # end of do block
  p           # print the pattern space
  b           # go to the end of the script, continue with next line
  :x          # the label x for goto commands
  p           # print the pattern space
  n           # load the next line in the pattern space (clearing old contents)
  bx          # goto the label x
  ' nomi
1
27.01.2020, 19:39
sed -n '/claudia/{p;Q}'

sed -n '           # don't print input
    /claudia/      # regex search
    {              # when match is found do
    p;             # print line
    Q              # quit sed, don't print last buffered line
    {              # end do block
1
27.01.2020, 19:39

Резюме

Синтаксис GNU:

sed '/claudio/{s//claudia/;:p;n;bp}' file

Или даже (использовать только один раз заменяемое слово:

sed '/\(claudi\)o/{s//\1a/;:p;n;bp}' file

Или, в синтаксисе POSIX:

sed -e '/claudio/{s//claudia/;:p' -e 'n;bp' -e '}' file

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

Деталь

Чтобы изменить только одну строку, необходимо выбрать только одну строку.

Используя1,/claudio/(из вашего вопроса ), выберите:

  • с первой строки (безусловно)
  • на следующую строку, содержащую строку claudio.
$ cat file
claudio 1
antonio 2
claudio 3
michele 4

$ sed -n '1,/claudio/{p}' file
claudio 1
antonio 2
claudio 3

Чтобы выбрать любую строку , содержащую claudio, используйте :

.
$ sed -n `/claudio/{p}` file
claudio 1
claudio 3

И чтобы выбрать только первыйclaudioв файле, используйте:

sed -n '/claudio/{p;q}' file
claudio 1

Затем вы можете сделать замену только в этой строке:

sed '/claudio/{s/claudio/claudia/;q}' file
claudia 1

Это изменит только первое вхождение совпадения с регулярным выражением в строке, даже если их может быть более одного, в первой строке, совпадающей с регулярным выражением.

Конечно, регулярное выражение /claudio/можно упростить до:

$ sed '/claudio/{s//claudia/;q}' file
claudia 1

И тогда единственное, чего не хватает, это напечатать все остальные строки без -измененных:

sed '/claudio/{s//claudia/;:p;n;bp}' file
5
27.01.2020, 19:39

Новая версия GNU sedподдерживает опцию -z.

Normally, sed reads a line by reading a string of characters up to the end-of-line character (new line or carriage return).
The GNU version of sed added a feature in version 4.2.2 to use the "NULL" character instead. This can be useful if you have files that use the NULL as a record separator. Some GNU utilities can generate output that uses a NULL instead a new line, such as "find. -print0" or "grep -lZ".

Вы можете использовать эту опцию, если хотите, чтобы sedработало над разными строками.

echo 'claudio
antonio
claudio
michele' | sed -z 's/claudio/claudia/'

возвращает

claudia
antonio
claudio
michele
8
27.01.2020, 19:39

Сначала направить некоторый вывод в awk

Затем вы можете использовать переменные awk для замены

cat someFile | awk '!x{x=sub("wordToReplace","wordThatIsReplaced")}1'

Обратите внимание на номер в конце.

Требуется, но может быть любым числом, я выбрал 1 для обозначения первого экземпляра.

0
06.05.2021, 22:21

Теги

Похожие вопросы