Sınırlayıcı üçlü boru sembolü “|||” ile iki dosyayı satır satır birleştirin


14

İki dilde aynı sayıda satır içeren iki paralel dosyam var ve bu iki dosyayı sınırlayıcı ile satır satır birleştirmeyi planlıyorum |||. Örneğin, iki dosya aşağıdaki gibidir:

Dosya:

1Mo 1,1 I love you.
1Mo 1,2 I like you.
Hi 1,3 I am hungry.
Hi 1,4 I am foolish.

Dosya B:

1Mo 1,1 Ich liebe dich.
1Mo 1,2 Ich mag dich.
Hi 1,3 Ich habe Durst.
Hi 1,4 Ich bin neu.

Beklenen çıktı şu şekildedir:

1Mo 1,1 I love you. ||| 1Mo 1,1 Ich liebe dich.
1Mo 1,2 I like you. ||| 1Mo 1,2 Ich mag dich.
Hi 1,3 I am hungry. ||| Hi 1,3 Ich habe Durst.
Hi 1,4 I am foolish. ||| Hi 1,4 Ich bin neu.

Bu pastekomutu denedim :

paste -d "|||" fileA fileB

Ancak döndürülen çıktı yalnızca bir boru içerir:

1Mo 1,1 I love you. |1Mo 1,1 Ich liebe dich.
1Mo 1,2 I like you. |1Mo 1,2 Ich mag dich.

Her bir çift boruyu işkembe borusuyla ayırmanın herhangi bir yolu var mı |||?


8
paste -d '|||' fileA - - fileB < /dev/null
Stéphane Chazelas

5
offtopic, ancak çevirileriniz doğru değil;) "Ich habe Durst" = Ben thisrty, "Ich bin neu" = Ben yeniyim ... mutlaka aptal olduğunuz anlamına gelmez. ... aslında Almanca öğreniyor olmanız durumunda ...
dave_alcarin

@ StéphaneChazelas Thx, ama çıktım hala sadece bir boru içeriyor ...
Frown

@dave_alcarin Dank sehr!
Frown

Yanıtlar:


20

İle POSIX'e yapıştırın :

:|paste -d ' ||| ' fileA - - - - fileB

pastetüm girdi dosyalarının karşılık gelen satırlarını birleştirir. Burada altı fileAdosyamız var, standart girişten dört kukla dosya -ve fileB.

Sınırlayıcılar listesi, bir boşluk, üç boru ve pastedairesel olarak kullanılacak sırayla bir boşluk içerir .

Altı dosyanın ilk satırı fileAiçin, ilk kukla dosya ile birleştirilecektir (hiçbir şey, no-op: operatöre teşekkürler ), üretin line1-fileA<space>.

İlk kukla dosya ikincisi bir boru ile birleştirilecek, üretilecek line1-fileA |, daha sonra ikinci kukla dosya üçüncü kukla dosya ile üretilecek line1-fileA ||, üçüncü kukla dosya dördüncü kukla dosya ile üretilecektir line1-fileA |||.

Ve dördüncü kukla dosya ile fileBüretin line1-fileA ||| line1-fileB.

Bu adım tüm hatlar için tekrarlanacaktır, size beklenen sonucu verecektir.


Kullanımı :|daha az yazım içindir ve temel olarak etkileşimli kabukta kullanılır. Bir komut dosyasında şunları kullanmalısınız:

</dev/null paste -d ' ||| ' fileA - - - - fileB

bir alt kabuğun ortaya çıkmasını önlemek için.


1
İçin +1 :|. zeki alternatif</dev/null
cas

4
... ve standart girişten 4 kukla dosyanın akıllı kullanımı için +1 - - - -, ancak bir dahaki sefere açıklama için birkaç satır bile yazabilirsiniz :)
Hastur

Teşekkürler, ama yine de bir boru ile çıktı alıyorum ...
Frown

@hui, komutu tüm çizgi ve boşluk karakterleri de dahil olmak üzere tam olarak verildi mi? İşletim sisteminiz nedir?
Stéphane Chazelas

:|paste -d '|' fileA - - fileBboşluk sınırlayıcı olmadan daha doğru sürümü verir.
Pål GD

7

Peki, bu sed, awk veya grep kullanmaz, ancak bash'da kolayca yapabilirsiniz. Komut:

(while IFS= read -r a <&3 && IFS= read -r b <&4; do echo "$a ||| $b"; done) 3<fileA 4<fileB

Yapıştır ile ilgili sorun, sınırlayıcının tek bir karakter olmasıdır. Ayrıca dönüştürmek için tek bir karakter ve sed kullanımı da ekleyebilirsiniz, ancak karakter giriş dosyasında zaten görünüyorsa hataya eğilimli olabilir.


2
Satır herhangi bir ters eğik çizgi karakteri içeriyorsa veya kısa çizgiyle başlarsa çözümünüz çalışmaz. IFS=Her birinden önce kullanmak istiyorsunuz read. Bunu kolayca yapabilirsiniz paste. Bkz Yanıtımı zamanda ve bu bir kullanmaktan kaçınmalısınız neden görmek whilekabuk komut döngü.
cuonglm

Dosyam için çalışıyor. Birçok Thx !!!
Frown

5

Awk (GNU) sürümü

awk '{printf ("%s ||| ", $0); getline < "fileB"; print $0 }' fileA

İle getlinede komuta awk, ayarlayabilirsiniz $0, gelecek giriş kaydından (sütunlar için tüm değişkenleri) getline < "filename"bir sonraki set $0belirtilen dosyadan.

getline <"file" Bir sonraki dosya kaydından $ 0 olarak ayarlayın; NF'yi ayarlayın.


Neden girişiminiz beklediğiniz gibi çalışmadı? Dan man pastebiz okuyabilir

-d, --delimiters=LIST
     reuse characters from LIST instead of TABs

ancak her sütun için bir sınırlayıcı kullanır .

Bu yüzden komut
paste -d '|*|*' fileA fileB fileA fileBbana şu satırları veriyor:

Hi 1,3 I am hungry.|Hi 1,3 Ich habe Durst.*Hi 1,3 I am hungry.|Hi 1,3 Ich...
Hi 1,4 I am foolish.|Hi 1,4 Ich bin neu.*Hi 1,4 I am foolish.|Hi 1,4 Ich...


sedOrijinal girişiminize yakın olsanız bile kaçınmayı önerdiğim bir çözüm, çünkü elde edilen davranışı orijinal amacınıza yatıyor:

 paste -d '|' fileA fileB | sed 's/|/|||/g'

Her bir kalıbı |yenisiyle değiştirdiğinizden kaçınmak için |||, ancak |verilerinizde boru simgesinin ( ) bulunmadığını varsaymanız gerekir , aksi takdirde özel durumlar ile uğraşmanız ve yan etkileri önlemek için kodu daha karmaşık hale getirmeniz gerekir.


Here String [ 1 ] yapısına sahip bir değişken<<<

 paste -d ' ||| ' fileA - - - - fileB  <<< ''

Boş dizeden veri alacak -d ' ||| '(boşluk, |, |, |, boşluk) ve 4 kukla dosya ( - - - -) ile 5 sınırlayıcı belirlersiniz ''.


GNU Awk 4.0.1, macun (GNU coreutils) 8.21 ve sed (GNU sed) 4.2.2 üzerinde test edilmiştir


Teşekkürler, awk komutu çalışıyor!
Frown

1
Rica ederim. sed(:-)) ve daha fazla yorumdan kaçınmak için bir örnek ekleyerek cevap güncellendi .
Hastur

4

Dairesel sınırlayıcıların ve kukla dosyaların sihrinden ve dramından kaçınmak istiyorsanız, sınırlayıcıyı yapıştırmadan önce bir dosyaya ekleyebilirsiniz:

paste <(sed 's/$/ |||/' filea) fileb

verir

1Mo 1,1 I love you. ||| 1Mo 1,1 Ich liebe dich.
1Mo 1,2 I like you. ||| 1Mo 1,2 Ich mag dich.
Hi 1,3 I am hungry. ||| Hi 1,3 Ich habe Durst.
Hi 1,4 I am foolish. |||    Hi 1,4 Ich bin neu.

Bunu basitlik için seviyorum. Ben "apend" değil, "prepend" demek istediğinizi düşünüyorum. Checkout Hastur'un bunun awk versiyonu için garip cevabı.
Wildcard

Proses ikamesini bir boruya değiştirmelisiniz, böylece onu destekleyen mermi sayısı sınırına sahip olmayacaksınız.
cuonglm

@Wildcard evet, başa, ama filea'ya eklemek için yeniden yazacağım. Ben awk bunun için biraz abartılı olduğunu düşünüyorum.
snth

@cuonglm doğru, ama netlik için borulardan kaçınmak istedim. Bir borunun kukla dosyalara benzemeye başlayacağını hissettim, ama
haklısın

0

bunu python'da da bu şekilde yapabilirsiniz.

lines1 = [ line.rstrip() for line in open("file1") ]
lines2 = [ line.rstrip() for line in open("file2") ]
for i in xrange((len(lines1))): print lines1[i] + " ||| " + lines2[i]
... 
1Mo 1,1 I love you. ||| 1Mo 1,1 Ich liebe dich.
1Mo 1,2 I like you. ||| 1Mo 1,2 Ich mag dich.
Hi 1,3 I am hungry. ||| Hi 1,3 Ich habe Durst.
Hi 1,4 I am foolish. ||| Hi 1,4 Ich bin neu.
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.