Sed bir dosyada sadece ilk olay yerine nasıl kullanılır?


217

Mevcut herhangi bir #includes önce ekstra bir yönerge ile C ++ kaynak dosyaları çok sayıda güncellemek istiyorum. Bu tür bir görev için, normalde dosyayı yeniden yazmak için sed ile küçük bir bash betiği kullanırım.

Nasıl alırım sedher geçtiği değiştirmek yerine bir dosyada bir dize sadece ilk geçtiği yerine?

Kullanırsam

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

# includes'in yerini alır.

Aynı şeyi başarmak için alternatif öneriler de kabul edilir.

Yanıtlar:


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---

veya isterseniz: Editörün notu: yalnızca GNU ile çalışır sed.

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

Kaynak


86
Sanırım 'ya da isterseniz' çözümünü tercih ediyorum. Ayrıca, cevapları açıklamak ve yanıtı sadece genelleştirmek yerine soruyu doğrudan ele almak ve sonra genelleştirmek iyi olur. Ama iyi cevap.
Jonathan Leffler

7
Mac kullanıcıları için FYI, 0'ı 1 ile değiştirmelisiniz, bu yüzden: sed '1, / RE / s // to_that /' dosyası
mhost

1
mhost Hayır, # 1 satırında desen bulunursa, desen başka bir satırdaysa değiştirilmez, ancak yine de bulunan ilk desendir. PS bu 0,sadecegnu sed
Jotne

11
Birisi lütfen 'veya tercih ediyorsanız' çözümünü açıklayabilir mi? "Kimden" kalıbını nereye koyacağımı bilmiyorum.
Jean-Luc Nacif Coelho

3
@ Jean-LucNacifCoelho: s//- yani boş bir normal ifade kullanmak - en son uygulanan normal ifade dolaylı olarak yeniden kullanılır; bu durumda RE,. Bu kullanışlı kısayol, saramanızdaki aralık biten normal ifadeyi çoğaltmanız gerekmediği anlamına gelir .
mklement0

289

sed"Banana" ile "Apple" ın ilk oluşumunu değiştirecek bir komut dosyası

Misal

     Input:      Output:

     Apple       Banana
     Apple       Apple
     Orange      Orange
     Apple       Apple

Bu basit komut dosyasıdır: Editörün notu: sadece GNU ile çalışır sed.

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

İlk iki parametre 0ve /Apple/aralık belirleyicidir. Bu s/Apple/Banana/aralık içinde yürütülen şey budur. Yani bu durumda "başlangıcında ( 0) ilk örneğine kadar olanlarla Appledeğiştirin Apple, Bananasadece Appleilkiyle değiştirilecektir.

Arka plan: Geleneksel sedolarak aralık belirteci de "buradan başlayın" ve "burada bitirin" (dahil) şeklindedir. Bununla birlikte, en düşük "başlangıç" ilk satırdır (satır 1) ve "burada son" ifadesi bir normal ifade ise, yalnızca "başlangıç" dan sonra bir sonraki satırda eşleşmeye çalışır, bu nedenle mümkün olan en erken son satırdır 2. Bu nedenle aralık dahil olduğu için, mümkün olan en küçük aralık "2 satır" ve en küçük başlangıç ​​aralığı hem satır 1 hem de 2'dir (yani satır 1'de bir olay varsa, satır 2'deki olaylar da değiştirilir, bu durumda istenmez ). GNUsed line 0, aralığın sonu olabilmesi için line 1"yalnızca ilk satır" aralığına izin vererek kendi başlangıcını "sözde" olarak belirtmeye izin verme uzantısını ekler

Veya basitleştirilmiş bir sürüm (boş bir RE benzeri //, kendisinden önce belirtileni yeniden kullanmak anlamına gelir, bu nedenle bu eşdeğerdir):

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

Kıvırcık parantezler komut için isteğe bağlıdırs , bu yüzden bu da eşdeğerdir:

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

Bütün bunlar sedsadece GNU üzerinde çalışıyor .

Homebrew kullanarak GNU sed'i OS X'e de kurabilirsiniz brew install gnu-sed.


167
insan diline çevrildi: 0 satırından başlayın, 'Apple' ile eşleşene kadar devam edin, ikameyi kıvırcık parantez içinde yürütün. cfr: grymoire.com/Unix/Sed.html#uh-29
mariotomo

8
OS X'te,sed: 1: "…": bad flag in substitute command: '}'
16'da ELLIOTTCABLE

5
OS X üzerinde @ELLIOTTCABLE kullanın sed -e '1s/Apple/Banana/;t' -e '1,/Apple/s//Banana/'. @ MikhailVS'in cevabından (şu anda) aşağıda.
djb

8
Parantez olmadan da çalışır:sed '0,/foo/s/foo/bar/'
Innokenty

5
Anladım sed: -e expression #1, char 3: unexpected , `` bununla
Jonathan

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

bu benim için çalıştı.

misal

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

Editörün notu: her ikisi de sadece GNU ile çalışır sed.


2
@Landys hala diğer satırlardaki örneklerin yerini alıyor; sadece ilk örnek değil
sarat

1
@sarat Evet, haklısın. sed '1,/pattern/s/pattern/replacement/' filenameyalnızca Mac'te "desen ilk satırda gerçekleşmeyecekse" çalışır. Doğru olmadığı için önceki yorumumu sileceğim. Ayrıntıları burada bulabilirsiniz ( linuxtopia.org/online_books/linux_tool_guides/the_sed_faq/… ). Andy'nin cevabı sadece GNU sed için çalışıyor, ancak Mac'teki cevap için değil.
Landys

45

Bir bakış , birçok yararlı ait mevcut cevapları ile tamamlanmaktadır açıklamalar :

Buradaki örneklerde basitleştirilmiş bir kullanım örneği kullanılmıştır: 'foo' kelimesini yalnızca ilk eşleşen satırdaki 'bar' ile değiştirin.
Kullanılması sayesinde ISO C tırnakla ( $'...') örnek giriş hatlarını sağlamak için bash, kshveya zshkabuk olarak kabul edilir.


sedYalnızca GNU :

Ben Hoffstein en anwswer GNU bir sağladığını gösterir bize uzantısı için için POSIX şartnamesed o aşağıdaki verir 2-adres formu : 0,/re/( rekeyfi bir normal ifade burada gösterir).

0,/re/normal ifadenin ilk satırda da eşleşmesini sağlar . Başka bir deyişle: Böyle bir adres maçları o limitini içeren bir karşı 1 hat yukarıya aralığını ve yaratacak re- ister re1 hattında veya sonraki satırda oluşur.

  • 1,/re/Bunu, ilk satırdan sonrakine reve sonraki satırlarda eşleşen çizgiye kadar uzanan bir aralık oluşturan POSIX uyumlu formla karşılaştırın ; diğer bir deyişle: 1. satırda meydana gelirse bir remaçın ilk tekrarını tespit etmez ve ayrıca en son kullanılan normal ifadenin yeniden kullanımı için steno kullanımını önler// (bir sonraki noktaya bakın). 1

Bir 0,/re/adresi s/.../.../, aynı normal ifadeyi kullanan bir (yerine koyma) çağrısıyla birleştirirseniz , komutunuz değiştirmeyi yalnızca eşleşen ilk satırda etkili bir şekilde gerçekleştirir re. en son uygulanan normal ifadeyi yeniden kullanmak için
sed kullanışlı bir kısayol sağlar : boş bir sınırlayıcı çifti// ,.

$ 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

sedBSD (macOS) gibi yalnızca POSIX özelliklerised ( GNU ile de çalışır sed):

Yana 0,/re/kullanılamaz ve form 1,/re/algılamaz reo (yukarıya bakınız) ilk satırında ortaya olursa, 1 hat için özel işlem gereklidir .

MikhailVS'nin cevabı , burada somut bir örnek haline getirilen teknikten bahsediyor:

$ 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

Not:

  • Boş normal ifade //kısayolu burada iki kez kullanılır: bir kez aralığın bitiş noktası için ve bir kez sçağrıda; her iki durumda da, normal ifade fooörtük olarak yeniden kullanılır, bu da onu kopyalamamıza izin verir, bu da hem daha kısa hem de daha sürdürülebilir bir kod sağlar.

  • POSIX sed, burada olduğu gibi, bir etiketin adından veya hatta çıkarılmasından sonra gibi belirli işlevlerden sonra gerçek satırsonlarına ihtiyaç duyar t; betiği stratejik olarak birden çok -eseçeneğe bölmek, gerçek bir yeni satır kullanmaya alternatiftir: -enormalde bir satırsonunun gitmesi gereken her komut dizisini sonlandırın .

1 s/foo/bar/fooorada bulunursa, yalnızca 1. satırın yerine geçer . Öyleyse t, komut dosyasının sonuna dallanır (satırda kalan komutları atlar). ( tBir etikete yalnızca en son sçağrı gerçek bir ikame gerçekleştirdiyse dallanır; bir etiket yokluğunda, burada olduğu gibi, komut dosyasının sonu dallanır).

Bu olduğu zaman, aralık adresi 1,//genellikle ilk geçtiği bulur, hat 2'den başlayan , edecek olup neticesinde, ve aralık olacak değil mevcut hat zaten, adres değerlendirilir çünkü işlenecek 2.

1 satırda eşleşen bir Tersine, 1,// olacak girilecek ve gerçek ilk maçı bulacaksınız.

Net etki, GNU ile aynıdır sedsitesindeki 0,/re/1st hattı ya da başka bir oluşup oluşmadığını değiştirilir, sadece ilk seferinde.


Aralık dışı yaklaşımlar

Potong cevabı gösteren döngü teknikleri bir dizi ihtiyacını bypass ; GNU sed sözdizimini kullandığı için POSIX uyumlu eşdeğerleri aşağıda verilmiştir :

Döngü tekniği 1: İlk eşleşmede ikame işlemini gerçekleştirin, ardından kalan çizgileri olduğu gibi yazdıran bir döngü girin :

$ 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

Döngü tekniği 2, yalnızca ufacık dosyalar için : tüm girişi belleğe okuyun, sonra tek bir değişiklik yapın .

$ 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/müteakip olan ve olmayan şeylerin örneklerini sunar s//:
- sed '1,/foo/ s/foo/bar/' <<<$'1foo\n2foo'verimler $'1bar\n2bar'; yani, her iki satır da güncellendi, çünkü satır numarası 11. satırla eşleşir ve regex /foo/- aralığın sonu - yalnızca sonraki satırdan başlayarak aranır. Bu nedenle, bu durumda her iki satır seçilir ve s/foo/bar/ikame her ikisinde de gerçekleştirilir.
- sed '1,/foo/ s//bar/' <<<$'1foo\n2foo\n3foo' başarısız : sed: first RE may not be empty(BSD / macOS) ve sed: -e expression #1, char 0: no previous regular expression(GNU) ile, çünkü 1. satır işlenirken ( 1aralıktan başlayan satır numarası nedeniyle ), henüz normal ifade uygulanmadığından,//hiçbir şey ifade etmiyor.
GNU'nun sedözel 0,/re/sözdizimi dışında, bir satır numarasıyla başlayan herhangi bir aralık etkili bir şekilde kullanılmasını engeller . //


25

Awk'yi benzer bir şey yapmak için kullanabilirsiniz.

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

Açıklama:

/#include/ && !done

Satır "#include" ile eşleştiğinde ve henüz işleme koyulmadığında {} arasında eylem ifadesini çalıştırır.

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

Bu #include "newfile.h" yazdırır, tırnaklardan kaçmamız gerekir. Sonra biten değişkeni 1 olarak ayarladık, bu yüzden daha fazla ekleme eklemiyoruz.

1;

Bu, "satırı yazdır" anlamına gelir - boş bir eylem varsayılan olarak tüm satırı yazdıran $ 0 yazdırır. Sed IMO'dan daha tek bir astar ve anlaşılması daha kolay :-)


4
Bu cevap güvenmek sed çözümleri, daha taşınabilir gnu sed vb .. (örn OS X'de sed berbat!)
Jay Taylor

1
Bu gerçekten daha anlaşılır, ancak benim için değiştirmek yerine bir satır ekliyor; kullanılan komut: awk '/version/ && !done {print " \"version\": \"'${NEWVERSION}'\""; done=1;}; 1;' package.json
Cereal Killer

burada da aynı, en anlaşılır komut, ancak bulunan dizenin yerine değiştirmek yerine bir satır ekliyor
Flion

1
Cevap oldukça okunabilir. İşte yeni bir satır eklemek yerine dizenin yerini alan sürümüm. awk '/#include/ && !done { gsub(/#include/, "include \"newfile.h\""); done=1}; 1' file.c
Orsiris de Jong

18

Linuxtop sed SSS üzerinde oldukça kapsamlı bir cevap koleksiyonu . Ayrıca, insanların verdiği bazı yanıtların sed'in GNU olmayan sürümü ile çalışmadığını vurgulamaktadır.

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

GNU olmayan sürümde

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

Ancak, bu sürüm gnu sed ile çalışmaz.

İşte her ikisiyle de çalışan bir sürüm:

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

örn:

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

Gerçekten de, Ubuntu Linux v16 ve FreeBSD v10.2 üzerinde çalışarak test edildi. Teşekkürler.
Sopalajo de Arrierez

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

Bu komut dosyası nasıl çalışır: 1 ile ilk arasındaki satırlar için #include (satır 1'den sonra), satır başlıyorsa #include, belirtilen satırı ekleyin.

Ancak, birinci #includesatır 1'de ise, hem satır 1 hem de sonraki sonraki #includesatırın başına satır eklenir. GNU kullanıyorsanız , doğru olanı (yerine ) yapacak sedbir uzantısı vardır .0,/^#include/1,


11

Sondaki olay sayısını ekleyin:

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

7
Ne yazık ki, bu işe yaramıyor. Dosyanın ilk tekrarını değil, dosyanın her satırındaki ilk tekrarlamayı değiştirir.
David Dibben

1
Ayrıca, standart bir sed özelliği değil, bir GNU sed uzantısıdır.
Jonathan Leffler

10
Hmmm ... zaman geçiyor. POSIX 2008/2013 sed, ile ikame komutunu belirtir: [2addr]s/BRE/replacement/flagsve "Bayrakların değeri, sıfır veya daha fazla olacaktır: n Yalnızca desen alanı içinde bulunan BRE'nin üçüncü gerçekleşmesi yerine geçer." Bu nedenle, en azından POSIX 2008'de, takip 1bir GNU seduzantısı değildir . Gerçekten de, SUS / POSIX 1997 standardında bile, bu desteklendi, bu yüzden 2008'de geri döndüm.
Jonathan Leffler

7

Olası bir çözüm:

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

Açıklama:

  • #include bulana kadar satırları okuyun, bu satırları yazdırın ve yeni döngüyü başlatın
  • yeni içerme satırını ekle
  • satırları okuyan bir döngü girin (varsayılan olarak sed de bu satırları yazdıracaktır), betiğin ilk kısmına buradan geri dönmeyeceğiz

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

Görünüşe göre son sed sürümlerinde ve boş etiketlerde bir şeyler değişti. cevabı güncelledi
mitchnull

4

Bu eski bir yazı olduğunu biliyorum ama kullandığım bir çözüm vardı:

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

Temel olarak ilk olayı yazdırmak ve orada durdurmak için grep kullanın. İlave olarak baskı numarası5:line . Sed içine boru ve çıkarın: ve daha sonra bir şey ile bir satır numarası kalır. Bunu son numarasına s /.*/ replace ekleyen sed'e ekleyin, bu da dosyada bir komut dosyası olarak çalışmak üzere son sed'e aktarılan 1 satırlık bir komut dosyasına neden olur.

eğer regex = #includeve replace = blahve grep'in ilk bulgusu 5. satırdaysa, son sed'e aktarılan veriler olacaktır 5s/.*/blah/.

İlk olay ilk satırda olsa bile çalışır.


Ben s ve bir linenumber dışında bir şey ile çok satırlı sed komut veya sed komutları nefret ediyorum bu yüzden bu yaklaşım ile gemide. İşte benim usecase için kullandığım (bash ile çalışır): filepath = / etc / hosts; patt = '^ \ (127 \ .0 \ .0 \ .1. * \)'; repl = '\ 1 newhostalias'; sed $ (IFS =: linearray = ($ (grep -E -m 1 -n "$ patt" "$ dosyayolu")) && echo $ {linearray [0]}) s / "$ patt" / "$ yanıt" / "$
dosyayolu

İşe yarıyor. Gerçi sadece sed -f -bazılarının olmadığını kabul edecek kadar akıllı olan
sed'lerle

3

Buraya, tüm satırlardaki (benim gibi) ilk kez bir karakteri değiştirmek için buraya geldiyse, bunu kullanın:

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

Örneğin 1'den 2'ye değiştirerek bunun yerine sadece ikinci a'nın yerine geçebilirsiniz.


2
Bunların hepsini, 's/a/b/'araçlarını match ave yapmanıza gerek yokdo just first match for every matching line
Samveen

Samveen ile birlikteyim. Ayrıca bu, burada sorulan soruya cevap vermez . Bu cevabı silmenizi tavsiye ederim.
Socowi

Soru "bir dosyadaki ilk olay" değil "bir satırdaki ilk olay"
Manuel Romeiro

3

GNU sed'in -zseçeneği ile tüm dosyayı sanki tek bir satırmış gibi işleyebilirsiniz. Bu şekilde a s/…/…/tüm dosyadaki ilk eşleşmenin yerine geçer. Unutmayın: s/…/…/yalnızca her satırdaki ilk eşleşmenin yerini alır, ancak -zseçenekle sedtüm dosyayı tek bir satır olarak ele alır.

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

Genel durumda, desen alanı artık sadece bir satır yerine tüm dosyayı tuttuğundan sed ifadenizi yeniden yazmanız gerekir. Bazı örnekler:

  • s/text.*//olarak yeniden yazılabilir s/text[^\n]*//. yeni satır karakteri hariç[^\n] her şeyle eşleşir . yeni satıra ulaşılana kadar tüm sembollerle eşleşecektir .[^\n]*text
  • s/^text//olarak yeniden yazılabilir s/(^|\n)text//.
  • s/text$//olarak yeniden yazılabilir s/text(\n|$)//.

2

Ben bir awk komut dosyası ile yapardı:

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

sonra awk ile çalıştırın:

awk -f awkscript headerfile.h > headerfilenew.h

özensiz olabilir, ben bu konuda yeniyim.


2

Alternatif bir öneri olarak edkomuta bakmak isteyebilirsiniz .

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

Sonunda bir RSS beslemesindeki her öğeye benzersiz bir zaman damgası eklemek için kullanılan bir Bash komut dosyasında çalışmak için aldım:

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

Yalnızca ilk olayı değiştirir.

${nowms}Perl betiği tarafından ayarlanan milisaniye cinsinden süre $counter, betiğin içindeki döngü denetimi için kullanılan bir sayaçtır \, komutun sonraki satırda devam etmesini sağlar.

Dosya okunur ve stdout bir çalışma dosyasına yönlendirilir.

Anladığım şekilde, 1,/====RSSpermalink====/sed'e bir aralık sınırlaması ayarlayarak ne zaman duracağını söyler ve sonra s/====RSSpermalink====/${nowms}/ilk dizeyi ikincisiyle değiştirmek için tanıdık sed komutudur.

Benim durumumda, değişkenli bir Bash betiğinde kullandığım için çift tırnak içine komutu koydum.


2

İşlenecek bir dosyada herhangi bir ifade olmaması durumunda FreeBSD kullanmak edve ed"eşleşme yok" hatasını önlemek 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

Bu kadar oldukça benzer timo 'ın cevabı ancak bir yıl sonra içinde ilave edilmiştir.
Jonathan Leffler

2

Bu sizin için işe yarayabilir (GNU sed):

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

veya bellek bir sorun değilse:

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

0

Aşağıdaki komut, bir dizenin dosyadaki ilk oluşumunu kaldırır. Boş çizgiyi de kaldırır. Bir xml dosyasında sunulur, ancak herhangi bir dosyayla çalışır.

Xml dosyalarıyla çalışıyorsanız ve bir etiketi kaldırmak istiyorsanız kullanışlıdır. Bu örnekte, "isTag" etiketinin ilk oluşumunu kaldırır.

Komut:

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

Kaynak dosya (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>

Sonuç dosyası (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 (oldukça eski) benim için işe yaramadı, ancak Linux 2.6, sed sürüm 4.1.5 üzerinde çalışıyor


Bu, önceki cevapların birçoğu ile aynı temel fikir gibi gözüküyor, sadece GNU ile çalıştığı aynı uyarıyla sed(bu nedenle Solaris ile çalışmadı). Bunu silmelisiniz, lütfen - cevap verdiğinizde zaten 4½ yaşında olan bir soruya gerçekten yeni bir bilgi sağlamıyor. Kabul edildi, işe yaramış bir örneği var, ancak sorunun bu kadar çok cevabı olduğunda bu tartışmalı bir değer.
Jonathan Leffler

0

Yeni bir şey değil, belki biraz daha somut bir cevap: sed -rn '0,/foo(bar).*/ s%%\1%p'

Örnek: şöyle xwininfo -name unity-launcherçıktı üretir:

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

Pencere kimliğini ayıklamak aşağıdakileri xwininfo -name unity-launcher|sed -rn '0,/^xwininfo: Window id: (0x[0-9a-fA-F]+).*/ s%%\1%p'üretir:

0x2200003

0

POSIXly (sed'de de geçerlidir), Yalnızca bir normal ifade kullanılır, yalnızca bir satır için bellek gerekir (her zamanki gibi):

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

Açıklaması:

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

Kullanım örneği, olaylarınızın dosyanızın her tarafına yayılmış olması olabilir, ancak tek endişenizin ilk 10, 20 veya 100 satırında olduğunu biliyorsunuzdur .

Daha sonra sadece bu satırları adreslemek sorunu düzeltir - OP'nin ifadesi sadece ilk bakışta olsa bile.

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

0

Burada olası bir çözüm, derleyiciye üstbilgiyi kaynak dosyalarda belirtilmeden eklemesini söylemek olabilir. GCC'de şu seçenekler vardır:

   -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'un derleyicisi / FI (zorunlu dahil) seçeneğine sahiptir.

Bu özellik, platform yapılandırması gibi bazı genel üstbilgiler için kullanışlı olabilir. Linux çekirdeği Makefile bunun için kullanıyor -include.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.