Sana katılıyorum olur - bu muhtemelen olan genel bir sorun. Bununla birlikte, bazı yaygın yardımcı programların, onu işlemek için bazı olanakları vardır.
nl
nl
örneğin, girdiyi mantıksal sayfalara-d
iki karakterli bir bölüm sınırlayıcı tarafından kaldırıldığı şekilde ayırır . Bir çizgide tek başına üç tekrar, bir başlığın başlangıcını gösterir , iki gövde ve bir altbilgi . Girişte bulunan bunlardan herhangi birini çıktıdaki boş bir satırla değiştirir - yazdırdığı tek boş satırdır
Örneğinizi başka bir bölüm içerecek şekilde değiştirdim ve yerleştirdim ./infile
. Yani şöyle görünüyor:
line A
line B
@@inline-code-start
line X
line Y
line Z
@@inline-code-end
line C
line D
@@start
line M
line N
line O
@@end
Sonra aşağıdakileri çalıştırdım:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end$/@@/' <infile |
nl -d@@ -ha -bn -w1
nl
mantıksal sayfalarda durumu biriktirdiği söylenebilir , ancak varsayılan olarak değildir. Bunun yerine, girdisinin çizgilerini stillere ve bölümlere göre numaralandıracaktır . Yani -ha
, tüm başlık satırlarını saymak ve bir vücut durumunda başladığı için hiçbir vücut çizgisi-bn
anlamına gelmez .
Bunu öğrenene kadar nl
herhangi bir girdi için kullanıyordum , ancak nl
bunun varsayılan -d
elimiter'e göre çıktıyı bozabileceğini fark ettikten sonra \:
, ona daha dikkatli olmayı öğrendim ve grep -nF ''
bunun yerine test edilmemiş girdi için kullanmaya başladım . Ancak o gün öğrenilen bir başka ders nl
, sed
yukarıdaki gibi sadece girişini biraz değiştirirseniz - bu gibi - diğer açılardan çok yararlı bir şekilde uygulanabileceğiydi .
ÇIKTI
line A
line B
1 line X
2 line Y
3 line Z
line C
line D
1 line M
2 line N
3 line O
İşte biraz daha nl
- numaralandırılmışlar dışındaki tüm satırların boşlukla nasıl başladığını yukarıda fark ettiniz mi? Tüm nl
sayılar hatları her kafasının içine karakter belirli sayıda ekler. Bu satırlar için numaralandırılmaz - boşluklar bile - numarasız satırların başına (idth -w
count + -s
eparator len) * boşlukları ekleyerek girintiyle her zaman eşleşir . Bu, numaralandırılmamış içeriği tam olarak numaralandırılmış içerikle karşılaştırarak ve çok az çaba sarf etmenize olanak tanır. Bunun sizin nl
için mantıksal bölümlere bölüneceğini ve -s
sayıladığı her satırın başına rastgele eğilimler ekleyebileceğinizi düşündüğünüzde, çıktısını işlemek oldukça kolaylaşır:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end/@@/; t
s/^\(@@\)\{1,3\}$/& /' <infile |
nl -d@@ -ha -bn -s' do something with the next line!
'
Yukarıdaki baskılar ...
line A
line B
1 do something with the next line!
line X
2 do something with the next line!
line Y
3 do something with the next line!
line Z
line C
line D
1 do something with the next line!
line M
2 do something with the next line!
line N
3 do something with the next line!
line O
GNU sed
Eğer nl
hedef uygulaması değil, o bir GNU sed
olabilir e
Bir maç bağlı için keyfi bir kabuk komutu xecute.
sed '/^@@.*start$/!b
s//nl <<\\@@/;:l;N
s/\(\n@@\)[^\n]*end$/\1/
Tl;e' <infile
Yukarıdaki sed
, ikame T
estini başarıyla geçip b
abel'e geri dönmeyi durduracak kadar desen uzayında girişi toplar :l
. e
Yaptığında , desen alanının geri kalan kısmı için burada bir belge nl
olarak gösterilen girdiyle xecutes yapar <<
.
İş akışı şu şekildedir:
/^@@.*start$/!b
- Bir eğer
^
tüm çizgi $
yok !
değil /
maç /
yukarıdaki kalıbı, o zaman olduğu b
senaryo dışına çiftçiliği ve autoprinted - yani bu noktadan itibaren sadece desen ile başladı çizgilerin bir dizi ile çalışıyorsanız üzerinde.
s//nl <<\\@@/
- boş
s//
alan /
, sed
eşleştirilmeye çalışılan son adresin yerini alır - dolayısıyla bu komut tüm @@.*start
satırın nl <<\\@@
yerine kullanılır.
:l;N
:
Komutu bir şube etiketi tanımlar - burada bir adlandırılmış set :l
Habil'i. N
Ext komutu bir takip desen boşluğa girişinin sonraki çizgisini ekler \n
ewline karakteri. Bu, örüntü alanında \n
ewline almanın birkaç yolundan biridir sed
- \n
ewline karakteri, sed
bunu bir süredir yapan bir der için kesin bir sınırlayıcıdır .
s/\(\n@@\)[^\n]*end$/\1/
- bu
s///
ikame ancak bir başlangıçla karşılaştıktan sonra ve yalnızca bir bitiş çizgisinin ilk takipinde başarılı olabilir . Sadece son \n
ewline'ın hemen ardından desen alanının @@.*end
sonunu işaretleyen bir desen alanı üzerinde hareket edecektir $
. Hareket ettiğinde, eşleşen dizenin tamamını \1
ilk \(
grupla değiştirir \)
veya \n@@
.
Tl
T
Bir etiket est komut dalları (eğer varsa) , başarılı bir ikame olarak bir giriş hattı paterni boşluğa çekilmiş son kez gerçekleşmediyse (w / gibi N
) . Bu \n
, son sınırlayıcınızla eşleşmeyen desen alanına her bir ewline eklendiğinde, T
est komutu başarısız olur ve abel'e geri döner :l
, bu sed
da N
ext satırında çekme ve başarılı olana kadar döngü ile sonuçlanır.
e
Son eşlemenin yerine koyma başarılı olduğunda ve komut dosyası başarısız bir T
est için geri dönmediğinde, aşağıdakine benzer bir komutu xecute sed
edecektir :e
l
nl <<\\@@\nline X\nline Y\nline Z\n@@$
Buradaki son satırı düzenleyerek kendiniz görebilirsiniz Tl;l;e
.
Yazdırır:
line A
line B
1 line X
2 line Y
3 line Z
line C
line D
1 line M
2 line N
3 line O
while ... read
Bunu yapmanın son bir yolu ve belki de en basit yolu, bir while read
döngü kullanmaktır , ancak iyi bir nedenden dolayı. Kabuk - (özellikle bir bash
kabuk) - girdiyi büyük miktarlarda veya sabit akışlarla işlemede tipik olarak oldukça uçsuzdur. Bu da mantıklıdır - kabuğun görevi karakterleri karaktere göre ele almak ve daha büyük şeyleri işleyebilecek diğer komutları çağırmaktır.
Ama önemlisi onun rolü hakkında kabuk olduğunu orada olmamalıdır read
bunun için belirtilen - girdinin overmuch değil o kadar çok tüketir veya eksik komutlar da çağrılar bırakılır bu süre içinde yeterince röle olmadığı noktaya giriş veya çıkışı tampon - bayta. Bu yüzden read
mükemmel bir giriş testi yapar - return
kalan giriş olup olmadığı hakkında bilgi ve bunu okumak için bir sonraki komutu çağırmanız gerekir - ancak aksi takdirde genellikle en iyi yol değildir.
Bununla birlikte, senkronize olarak girişi işlemek için birinin nasıl kullanılabileceğine read
ve diğer komutlara bir örnek :
while IFS= read -r line &&
case $line in (@@*start) :;; (*)
printf %s\\n "$line"
sed -un "/^@@.*start$/q;p";;
esac;do sed -un "/^@@.*end$/q;=;p" |
paste -d: - -
done <infile
Her yinelemede gerçekleşen ilk şey read
bir çizgi çeker. Başarılı olursa, döngü henüz EOF'ye çarpmadığı anlamına gelir ve bu nedenle case
bir başlangıç sınırlayıcıyla eşleştiğinde do
blok hemen yürütülür. Else, onu printf
yazdırır ve denir.$line
read
sed
sed
olacak p
karşılaştığı dek her satırını Rint başlangıç o zaman - işaretleyici q
tamamen girişini UITS. -u
Nbuffered anahtarı GNU için gerekli olan sed
o açgözlülükle aksi ziyade tampon, ancak çünkü - spec göre - diğer POSIX sed
lar herhangi bir özel göz olmadan çalışması gerekir - bu yüzden sürece <infile
normal bir dosyadır.
İlk sed
q
uyduğunda, kabuk , son işaretiyle karşılaşana kadar her satırı yazdıran do
başka bir çağıran döngü bloğunu yürütür . Bu borular etmek çıkışını , onların her satırda bir satır numaralarını yazdırır çünkü. Bunun gibi:sed
paste
1
line M
2
line N
3
line O
paste
daha sonra bunları :
karakterlere yapıştırır ve tüm çıktı şuna benzer:
line A
line B
1:line X
2:line Y
3:line Z
line C
line D
1:line M
2:line N
3:line O
Bunlar sadece örnektir - burada testte veya bloklarda her şey yapılabilir, ancak ilk yardımcı program çok fazla girdi tüketmemelidir.
İlgili tüm yardımcı programlar aynı girdiyi okur ve sonuçlarını kendi sırayla yazdırır. Farklı programları diğerlerinden daha tampon çünkü - - Bu tür bir şey asmak için zor olabilir ancak genellikle güvenebileceğiniz dd
, head
ve sed
doğru olanı yapmak (GNU için, gerçi sed
, sen cli-şalterini gerekir) ve her zaman güvenebilmelisiniz read
- çünkü doğa gereği çok yavaştır . Bu yüzden yukarıdaki döngü bunu giriş bloğu başına sadece bir kez çağırır.
nl
devlet biriktirmek zorunda değildir . Bak aznl -d
sizin kontrol etmek veman
/info
hakkında bilgi için sayfalarınl
bireyin bölüm sınırlayıcı .