Як використовувати sed для заміни лише першого появи у файлі?


217

Я хотів би оновити велику кількість вихідних файлів C ++ додатковими директивами включення перед будь-якими існуючими #includes. Для такого завдання я зазвичай використовую невеликий скрипт bash з sed, щоб переписати файл.

Як я можу sedзамінити лише перше виникнення рядка у файлі, а не замінювати кожне виникнення?

Якщо я користуюся

sed s/#include/#include "newfile.h"\n#include/

він замінює всі #includes.

Альтернативні пропозиції, щоб досягти того самого, також вітаються.

Відповіді:


135
 # sed script to change "foo" to "bar" only on the first occurrence
 1{x;s/^/first/;x;}
 1,/foo/{x;/first/s///;x;s/foo/bar/;}
 #---end of script---

або, якщо вам зручніше: Примітка редактора: працює лише з GNU sed .

sed '0,/foo/s//bar/' file 

Джерело


86
Я думаю, що я віддаю перевагу рішенню "або якщо ви віддаєте перевагу". Було б також добре пояснити відповіді - і змусити відповідь вирішити питання безпосередньо, а потім узагальнити, а не лише узагальнити. Але хороша відповідь.
Джонатан Леффлер

7
FYI для користувачів Mac, ви повинні замінити 0 на 1, так: sed '1, / RE / s // to_that /' файл
mhost

1
@mhost Ні, він замінить, якщо шаблон знайдений у рядку №1, а не, якщо шаблон знаходиться в іншій лінії, але все-таки є першим знайденим шаблоном. PS слід зазначити, що це 0,працює лише зgnu sed
Jotne

11
Чи може хтось пояснити, будь ласка, рішення "чи, якщо ви віддаєте перевагу"? Я не знаю, куди подіти схему "від".
Жан-Люк Нациф Коельо

3
@ Jean-LucNacifCoelho: використання s//- тобто порожній регулярний вираз - означає, що останній раз застосований регулярний вираз неявно повторно використовується; у цьому випадку RE. Цей зручний ярлик означає, що вам не доведеться дублювати регулярний регулярний вираз у своєму sдзвінку.
mklement0

289

sedСкрипт , який буде замінити тільки перше входження «Яблука» на «банані»

Приклад

     Input:      Output:

     Apple       Banana
     Apple       Apple
     Orange      Orange
     Apple       Apple

Це простий сценарій: Примітка редактора: працює лише з GNU sed .

sed '0,/Apple/{s/Apple/Banana/}' input_filename

Перші два параметри 0і /Apple/є специфікатором діапазону. Це s/Apple/Banana/те, що виконується в межах цього діапазону. Тож у цьому випадку "в межах від початку ( 0) до першої інстанції Appleзамініть Appleна Banana. Заміняється лише перший Apple.

Передумови: У традиційних sedспецифікаторах діапазону також є "почати тут" і "закінчити тут" (включно). Однак найнижчим "початком" є перший рядок (рядок 1), і якщо "кінець тут" є регулярним виразом, то він намагається відповідати лише на наступному рядку після "початку", тому самий ранній кінець - рядок 2. Отже, оскільки діапазон включений, найменший можливий діапазон - "2 рядки", а найменший початковий діапазон - це обидва рядки 1 і 2 (тобто, якщо є подія на лінії 1, входження в рядку 2 також будуть змінені, не бажано в цьому випадку ). GNUsed додає власне розширення, дозволяючи вказати початок як "псевдо", line 0щоб кінець діапазону міг бути line 1, дозволяючи йому діапазон "тільки перший рядок"

Або спрощена версія (порожній RE Like //означає повторне використання зазначеного раніше, тому це еквівалентно):

sed '0,/Apple/{s//Banana/}' input_filename

А фігурні дужки необов’язкові для sкоманди, тому це також рівнозначно:

sed '0,/Apple/s//Banana/' input_filename

Усі вони працюють sedлише в GNU .

Ви також можете встановити GNU sed на OS X за допомогою homebrew brew install gnu-sed.


166
перекладено на людську мову: починайте з рядка 0, продовжуйте, доки не будете відповідати "Apple", виконайте заміну у фігурних дужках. cfr
mariotomo

8
На OS X я потрапляюsed: 1: "…": bad flag in substitute command: '}'
ELLIOTTCABLE

5
@ELLIOTTCABLE на OS X, використовуйте sed -e '1s/Apple/Banana/;t' -e '1,/Apple/s//Banana/'. Від відповіді @ MihailVS (на даний момент) вниз нижче.
djb

8
Працює і без дужок:sed '0,/foo/s/foo/bar/'
Innokenty

5
Я розумію sed: -e expression #1, char 3: unexpected , '' з цим
Джонатан

56
sed '0,/pattern/s/pattern/replacement/' filename

це працювало для мене.

приклад

sed '0,/<Menu>/s/<Menu>/<Menu><Menu>Sub menu<\/Menu>/' try.txt > abc.txt

Примітка редактора: обидва працюють лише з GNU sed .


2
@Landys це все ще замінює екземпляри в інших рядках; не лише перша інстанція
сарат

1
@sarat Так, ти маєш рацію. sed '1,/pattern/s/pattern/replacement/' filenameпрацює лише в тому випадку, якщо "шаблон не відбудеться в першому рядку" на Mac. Я видалю попередній коментар, оскільки він не є точним. Детальну інформацію можна знайти тут ( linuxtopia.org/online_books/linux_tool_guides/the_sed_faq/… ). Відповідь Енді працює лише для GNU sed, але не для Mac.
Лендіс

45

Огляд з багатьох корисних існуючих відповідей , доповнених з поясненнями :

У прикладах тут використовується спрощений випадок використання: замініть слово "foo" на "bar" лише в першому рядку, що відповідає.
Завдяки використанню ANSI C-рядків в лапках ( $'...') , щоб забезпечити вибірки вхідних ліній, bash, kshабо zshпередбачаються в якості оболонки.


GNU sed :

Повідомлення Бена Гофштейна показує нам, що GNU надає розширення до специфікації POSIX,sed що дозволяє отримати наступну форму 2-адрес : 0,/re/(тут reпредставлений довільний регулярний вираз).

0,/re/дозволяє також регулярний вираз підходити до першого рядка . Іншими словами: така адреса створить діапазон від 1-го рядка до та включає рядок, який відповідає re- будь то reв 1-му або наступному рядку.

  • Порівняйте це з POSIX-сумісної формі 1,/re/, що створює діапазон , який відповідає на 1 - й лінії до і включаючи лінію, матчі reна наступних рядках; Іншими словами: це не виявить першого виникнення reвідповідності, якщо воно трапиться на 1-му рядку, а також запобігає використанню скорочень// для повторного використання останнього використовуваного регулярного виразу (див. наступний пункт). 1

Якщо ви поєднаєте 0,/re/адресу з s/.../.../викликом (заміщення), який використовує той самий регулярний вираз, ваша команда буде ефективно виконувати заміну лише в першому рядку, який відповідає re.
sedзабезпечує зручний ярлик для багаторазового використання самого останнього застосовується регулярне вираз : порожній пари роздільників,// .

$ sed '0,/foo/ s//bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo' 
1st bar         # only 1st match of 'foo' replaced
Unrelated
2nd foo
3rd foo

POSIX-функції, sedтакі як BSD (macOS)sed (також працюватиме з GNU sed ):

Оскільки 0,/re/його не можна використовувати, і форма 1,/re/не виявить, reякщо це трапляється на першому рядку (див. Вище), потрібне спеціальне оброблення для першого рядка .

Відповідь Михайловича згадує техніку, наведену тут на конкретному прикладі:

$ sed -e '1 s/foo/bar/; t' -e '1,// s//bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar         # only 1st match of 'foo' replaced
Unrelated
2nd foo
3rd foo

Примітка:

  • Тут //використовується двічі ярлик порожнього регулярного виразу : один раз для кінцевої точки діапазону та один раз для sвиклику; в обох випадках регекс fooнеявно повторно використовується, що дозволяє нам не дублювати його, що робить як коротший, так і більш підтримуваний код.

  • POSIX sedпотребує фактичних нових рядків після певних функцій, наприклад, після назви мітки або навіть її пропуску, як це відбувається у tнас; стратегічне розбиття сценарію на кілька -eваріантів є альтернативою використанню фактичних нових рядків: закінчуйте кожен -eфрагмент сценарію, куди, як правило, потрібно пройти новий рядок.

1 s/foo/bar/заміняється лише fooна 1-му рядку, якщо він знайдений там. Якщо так, tгілки до кінця сценарію (пропускає залишилися команди у рядку). ( tФункція переходить на мітку лише у тому випадку, якщо останній sвиклик здійснив фактичну заміну; за відсутності мітки, як це відбувається у кінці сценарію, розгалужується на).

Коли це станеться, адреса діапазону 1,//, яка зазвичай знаходить перше виникнення, починаючи з рядка 2 , не збігається, і діапазон не буде оброблятися, оскільки адреса оцінюється, коли поточний рядок вже є 2.

І навпаки, якщо на 1-му рядку 1,// не буде збігу, буде введено і знайдеться справжній перший збіг.

Чистий ефект такий же , як і з GNU sed«s 0,/re/: тільки перше входження замінюється, чи відбувається це на 1 - й лінії , або будь-який інший.


Підходи без діапазону

Відповідь Potong в демонструє петльові методи , які обходять необхідність в діапазоні ; оскільки він використовує синтаксис GNU sed , ось сумісні з POSIX еквіваленти :

Техніка циклу 1: У першому матчі виконайте підміну, а потім введіть цикл, який просто друкує решта рядків як є :

$ sed -e '/foo/ {s//bar/; ' -e ':a' -e '$!{n;ba' -e '};}' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar
Unrelated
2nd foo
3rd foo

Техніка циклу 2, лише для невеликих файлів : прочитайте весь вхід у пам'ять, після чого виконайте одну заміну на ній .

$ sed -e ':a' -e '$!{N;ba' -e '}; s/foo/bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar
Unrelated
2nd foo
3rd foo

1 1.61803 наводить приклади того, що відбувається з 1,/re/наступним і без них s//:
- sed '1,/foo/ s/foo/bar/' <<<$'1foo\n2foo'врожайність $'1bar\n2bar'; тобто обидва рядки були оновлені, оскільки номер рядка 1відповідає 1-му рядку, а регулярний вираз /foo/- кінець діапазону - шукається лише для початку в наступному рядку. Тому обидва рядки вибираються в цьому випадку, а s/foo/bar/заміна виконується в обох.
- sed '1,/foo/ s//bar/' <<<$'1foo\n2foo\n3foo' не вдається : з sed: first RE may not be empty(BSD / macOS) і sed: -e expression #1, char 0: no previous regular expression(GNU), оскільки під час обробки 1-го рядка (через номер рядка, що 1починає діапазон), ще не застосовано регулярний вираз,//не посилається ні на що.
За винятком sedспеціального 0,/re/синтаксису GNU , будь-який діапазон, що починається з номера рядка, фактично виключає використання //.


25

Ви можете використовувати awk, щоб зробити щось подібне ..

awk '/#include/ && !done { print "#include \"newfile.h\""; done=1;}; 1;' file.c

Пояснення:

/#include/ && !done

Запускає оператор дії {}, коли рядок відповідає "#include", і ми його ще не обробили.

{print "#include \"newfile.h\""; done=1;}

Це друкує #include "newfile.h", нам потрібно уникати цитат. Потім ми встановлюємо виконану змінну до 1, тому ми не додаємо більше включених.

1;

Це означає "роздрукувати рядок" - порожня дія за замовчуванням для друку $ 0, яка друкує весь рядок. Один лайнер і простіший для розуміння, ніж sed IMO :-)


4
Ця відповідь є більш портативною, ніж рішення sed, які покладаються на gnu sed тощо. (Наприклад, sed в OS-X смокче!)
Jay Taylor

1
Це справді зрозуміліше, але для мене він додає рядок замість того, щоб замінити його; команда використовується: awk '/version/ && !done {print " \"version\": \"'${NEWVERSION}'\""; done=1;}; 1;' package.json
Зерновий вбивця

те саме тут, найбільш зрозуміла команда, але вона додає рядок над знайденою рядком замість того, щоб замінити її
Flion

1
Відповідь досить читабельна. Ось моя версія, яка замінює рядок замість додавання нового рядка. awk '/#include/ && !done { gsub(/#include/, "include \"newfile.h\""); done=1}; 1' file.c
Орсіріс де Йонг

18

Досить вичерпна колекція відповідей на FAQ на linuxtopia sed . Він також підкреслює, що деякі відповіді, надані людьми, не працюватимуть із не-GNU версією sed, наприклад

sed '0,/RE/s//to_that/' file

у не-GNU-версії доведеться бути

sed -e '1s/RE/to_that/;t' -e '1,/RE/s//to_that/'

Однак ця версія не працюватиме з gnu sed.

Ось версія, яка працює з обома:

-e '/RE/{s//to_that/;:a' -e '$!N;$!ba' -e '}'

колишній:

sed -e '/Apple/{s//Banana/;:a' -e '$!N;$!ba' -e '}' filename

Дійсно, перевірено на Ubuntu Linux v16 та FreeBSD v10.2. Дякую тобі.
Sopalajo de Arrierez

12
#!/bin/sed -f
1,/^#include/ {
    /^#include/i\
#include "newfile.h"
}

Як працює цей скрипт: для рядків між 1 та першим #include(після рядка 1), якщо рядок починається з #include, тоді додайте вказаний рядок.

Однак якщо перший #includeзнаходиться в рядку 1, тоді і для першого, і для наступного наступного #includeрядка буде попередньо попереджений. Якщо ви використовуєте GNU sed, він має розширення, де 0,/^#include/(замість 1,) зробить правильно.


11

Просто додайте кількість зустрічей наприкінці:

sed s/#include/#include "newfile.h"\n#include/1

7
На жаль, це не працює. Він замінює саме перше виникнення у кожному рядку файлу, а не перше виникнення у файлі.
Девід Діббен

1
Крім того, це розширення sed GNU, а не стандартна функція sed.
Джонатан Леффлер

10
Гммм ... час проходить. POSIX 2008/2013 для sedвказує команду-замінник з: [2addr]s/BRE/replacement/flagsта зазначає, що "Значення прапорів має бути нульовим або більше: n Замінити для n-го появи лише BRE, знайденого в просторі шаблону". Таким чином, принаймні в POSIX 2008, трейлінг 1не є sedрозширенням GNU . Дійсно, навіть у стандарті SUS / POSIX 1997 це було підтримано, тому я сильно вийшов з ладу ще в 2008 році.
Джонатан Леффлер,

7

Можливе рішення:

    /#include/!{p;d;}
    i\
    #include "newfile.h"
    :a
    n
    ba

Пояснення:

  • читайте рядки, поки не знайдемо #include, надрукуйте ці рядки, а потім почніть новий цикл
  • вставити новий рядок включення
  • введіть цикл, який просто читає рядки (типово sed буде також друкувати ці рядки), ми не повернемося до першої частини сценарію звідси

sed: file me4.sed line 4: ":" lacks a label
rogerdpack

мабуть, щось змінилося в останніх версіях sed, і порожні мітки більше не дозволені. оновив відповідь
mitchnull

4

Я знаю, що це стара публікація, але у мене було рішення, яке я використовував:

grep -E -m 1 -n 'old' file | sed 's/:.*$//' - | sed 's/$/s\/old\/new\//' - | sed -f - file

В основному використовуйте grep, щоб надрукувати перше явище і зупинитися на цьому. Додатково друкуйте номер рядка, тобто 5:line. Вставте в sed і вийміть: і все після цього, вам просто залишиться номер рядка. Переконайтеся в sed, який додає s /.*/ заміну до кінцевого номера, що призводить до 1-го рядкового сценарію, який передається в останній sed для запуску як сценарій у файлі.

тож якщо regex = #includeі замінити = blahі перша знахідка grep знайдеться в рядку 5, то дані, передані в останній sed, будуть 5s/.*/blah/.

Працює, навіть якщо перше виникнення є на першому рядку.


Я дуже ненавиджу багаторядкові сценарії sed або команди sed з чим-небудь, крім s та проміжною кількістю, тому я борюся з таким підходом. Ось, що я використав для мого використання (працює з bash): filepath = / etc / hosts; patt = '^ \ (127 \ .0 \ .0 \ .1. * \)'; repl = '\ 1 newhostalias'; sed $ (IFS =: linearray = ($ (grep -E -m 1 -n "$ patt" "$ filepath")) && echo $ {linearray [0]}) s / "$ patt" / "$ repl" / "$ filepath"
parity3

Це працює. Хоча тільки з sed, які досить розумні, щоб прийняти sed -f -якісь ні, але ви можете
обійтись

3

Якщо хтось прийшов сюди, щоб замінити символ для першого появи у всіх рядках (як я), використовуйте це:

sed '/old/s/old/new/1' file

-bash-4.2$ cat file
123a456a789a
12a34a56
a12
-bash-4.2$ sed '/a/s/a/b/1' file
123b456a789a
12b34a56
b12

Змінивши, наприклад, 1 на 2, ви можете замість цього замінити лише всі другі.


2
Вам не потрібно робити все це, 's/a/b/'значить match a, іdo just first match for every matching line
Самвен

Я з Самвіном. Також це не дає відповіді на поставлене тут питання . Я б радив видалити цю відповідь.
Socowi

Питання було "перше виникнення у файлі", а не "перше виникнення у рядку"
Мануель

3

За допомогою параметра GNU sed -zви могли обробити весь файл так, ніби це був лише один рядок. Таким чином a s/…/…/замінить лише першу відповідність у всьому файлі. Пам’ятайте: s/…/…/замінює лише першу відповідність у кожному рядку, але з -zопцією sedрозглядає весь файл як один рядок.

sed -z 's/#include/#include "newfile.h"\n#include'

У загальному випадку вам доведеться переписати вираз sed, оскільки в просторі шаблону тепер міститься весь файл, а не лише один рядок. Деякі приклади:

  • s/text.*//можна переписати як s/text[^\n]*//. [^\n]відповідає всім, крім символу нового рядка. [^\n]*відповідатиме всім символам після того, textяк буде досягнуто новий рядок.
  • s/^text//можна переписати як s/(^|\n)text//.
  • s/text$//можна переписати як s/text(\n|$)//.

2

Я би зробив це за допомогою awk-сценарію:

BEGIN {i=0}
(i==0) && /#include/ {print "#include \"newfile.h\""; i=1}
{print $0}    
END {}

потім запустіть її з awk:

awk -f awkscript headerfile.h > headerfilenew.h

може бути неохайним, я новачок у цьому.


2

В якості альтернативної пропозиції ви можете переглянути edкоманду.

man 1 ed

teststr='
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
'

# for in-place file editing use "ed -s file" and replace ",p" with "w"
# cf. http://wiki.bash-hackers.org/howto/edit-ed
cat <<-'EOF' | sed -e 's/^ *//' -e 's/ *$//' | ed -s <(echo "$teststr")
   H
   /# *include/i
   #include "newfile.h"
   .
   ,p
   q
EOF

2

Нарешті я отримав це для роботи в сценарії Bash, який використовується для вставки унікальної часової позначки кожного елемента в RSS-канал:

        sed "1,/====RSSpermalink====/s/====RSSpermalink====/${nowms}/" \
            production-feed2.xml.tmp2 > production-feed2.xml.tmp.$counter

Це змінює лише перше виникнення.

${nowms}- час у мілісекундах, встановлений сценарієм Perl, $counterє лічильником, який використовується для керування циклом у сценарії, \дозволяє продовжувати команду в наступному рядку.

Файл читається, а stdout переспрямовується на робочий файл.

Те, як я це розумію, 1,/====RSSpermalink====/підказує sed, коли слід зупинитись, встановивши обмеження діапазону, а потім s/====RSSpermalink====/${nowms}/знайома команда sed замінити перший рядок другим.

У моєму випадку я кладу команду в подвійні лапки, оскільки я використовую її в сценарії Bash зі змінними.


2

Використання FreeBSD ed та уникнення edпомилки "без збігу", якщо includeу файлі не обробляється повідомлення:

teststr='
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
'

# using FreeBSD ed
# to avoid ed's "no match" error, see
# *emphasized text*http://codesnippets.joyent.com/posts/show/11917 
cat <<-'EOF' | sed -e 's/^ *//' -e 's/ *$//' | ed -s <(echo "$teststr")
   H
   ,g/# *include/u\
   u\
   i\
   #include "newfile.h"\
   .
   ,p
   q
EOF

Це дивно схоже на Timo «s відповідь , але був доданий більше року тому.
Джонатан Леффлер

2

Це може допомогти вам (GNU sed):

sed -si '/#include/{s//& "newfile.h\n&/;:a;$!{n;ba}}' file1 file2 file....

або якщо пам'ять не є проблемою:

sed -si ':a;$!{N;ba};s/#include/& "newfile.h\n&/' file1 file2 file...

0

Наступна команда видаляє перше виникнення рядка у файлі. Він також видаляє порожній рядок. Він представлений у файлі xml, але він би працював з будь-яким файлом.

Корисно, якщо ви працюєте з файлами xml і хочете видалити тег. У цьому прикладі він видаляє перше виникнення тегу "isTag".

Команда:

sed -e 0,/'<isTag>false<\/isTag>'/{s/'<isTag>false<\/isTag>'//}  -e 's/ *$//' -e  '/^$/d'  source.txt > output.txt

Вихідний файл (source.txt)

<xml>
    <testdata>
        <canUseUpdate>true</canUseUpdate>
        <isTag>false</isTag>
        <moduleLocations>
            <module>esa_jee6</module>
            <isTag>false</isTag>
        </moduleLocations>
        <node>
            <isTag>false</isTag>
        </node>
    </testdata>
</xml>

Файл результату (output.txt)

<xml>
    <testdata>
        <canUseUpdate>true</canUseUpdate>
        <moduleLocations>
            <module>esa_jee6</module>
            <isTag>false</isTag>
        </moduleLocations>
        <node>
            <isTag>false</isTag>
        </node>
    </testdata>
</xml>

ps: він не працював для мене на Solaris SunOS 5.10 (досить старий), але він працює на Linux 2.6, sed версія 4.1.5


Це надзвичайно схоже на ту саму основну ідею, як і ряд попередніх відповідей, з тим самим застереженням, що вона працює лише з GNU sed(отже, вона не працювала з Solaris). Вам слід видалити це, будь ласка - воно дійсно не дає нової відмінної інформації на запитання, якому вже було півтора роки, коли ви відповіли. Зрозуміло, у нього є спрацьований приклад, але це є дискусійним значенням, коли на питання є стільки ж відповідей, як на цей.
Джонатан Леффлер

0

Нічого нового, але, можливо, трохи конкретнішої відповіді: sed -rn '0,/foo(bar).*/ s%%\1%p'

Приклад: xwininfo -name unity-launcherотримує вихід типу:

xwininfo: Window id: 0x2200003 "unity-launcher"

  Absolute upper-left X:  -2980
  Absolute upper-left Y:  -198
  Relative upper-left X:  0
  Relative upper-left Y:  0
  Width: 2880
  Height: 98
  Depth: 24
  Visual: 0x21
  Visual Class: TrueColor
  Border width: 0
  Class: InputOutput
  Colormap: 0x20 (installed)
  Bit Gravity State: ForgetGravity
  Window Gravity State: NorthWestGravity
  Backing Store State: NotUseful
  Save Under State: no
  Map State: IsViewable
  Override Redirect State: no
  Corners:  +-2980+-198  -2980+-198  -2980-1900  +-2980-1900
  -geometry 2880x98+-2980+-198

Витяг ідентифікатора вікна з xwininfo -name unity-launcher|sed -rn '0,/^xwininfo: Window id: (0x[0-9a-fA-F]+).*/ s%%\1%p'продукує:

0x2200003

0

POSIXly (також діє в sed), лише один використовуваний регулярний вираз, потрібна пам'ять лише для одного рядка (як зазвичай):

sed '/\(#include\).*/!b;//{h;s//\1 "newfile.h"/;G};:1;n;b1'

Пояснили:

sed '
/\(#include\).*/!b          # Only one regex used. On lines not matching
                            # the text  `#include` **yet**,
                            # branch to end, cause the default print. Re-start.
//{                         # On first line matching previous regex.
    h                       # hold the line.
    s//\1 "newfile.h"/      # append ` "newfile.h"` to the `#include` matched.
    G                       # append a newline.
  }                         # end of replacement.
:1                          # Once **one** replacement got done (the first match)
n                           # Loop continually reading a line each time
b1                          # and printing it by default.
'                           # end of sed script.

0

Випадком використання може бути те, що ваші випадки поширюються по всьому файлу, але ви знаєте, що ваша проблема полягає лише в перших 10, 20 або 100 рядках.

Тоді просто звернення до цих рядків вирішує цю проблему - навіть якщо формулювання ОП стосується лише спочатку.

sed '1,10s/#include/#include "newfile.h"\n#include/'

0

Тут можливим рішенням може бути сказати компілятору включити заголовок без його згадування у вихідних файлах. У GCC є такі варіанти:

   -include file
       Process file as if "#include "file"" appeared as the first line of
       the primary source file.  However, the first directory searched for
       file is the preprocessor's working directory instead of the
       directory containing the main source file.  If not found there, it
       is searched for in the remainder of the "#include "..."" search
       chain as normal.

       If multiple -include options are given, the files are included in
       the order they appear on the command line.

   -imacros file
       Exactly like -include, except that any output produced by scanning
       file is thrown away.  Macros it defines remain defined.  This
       allows you to acquire all the macros from a header without also
       processing its declarations.

       All files specified by -imacros are processed before all files
       specified by -include.

Компілятор Microsoft має опцію / FI (примусовий включення).

Ця функція може бути зручною для деяких загальних заголовків, наприклад конфігурації платформи. Makefile ядра Linux використовує -includeдля цього.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.