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.