ผสานสองไฟล์ทีละบรรทัดด้วยสัญลักษณ์สามท่อคั่น "|||"


14

|||ฉันมีสองไฟล์แบบคู่ขนานกับจำนวนเดียวกันของเส้นในสองภาษาและแผนการที่จะผสานเหล่านี้สายสองไฟล์โดยสอดคล้องกับตัวคั่น เช่นทั้งสองไฟล์มีดังนี้:

ไฟล์ A:

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

ไฟล์ 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.

ผลลัพธ์ที่คาดหวังเป็นดังนี้:

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.

ฉันลองpasteคำสั่งเช่น:

paste -d "|||" fileA fileB

แต่เอาต์พุตที่ส่งคืนจะมีเพียงไพพ์เดียวเช่น:

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

มีวิธีใดที่จะแยกแต่ละคู่ของเส้นด้วยท่อผ้าขี้ริ้ว|||?


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

5
ผิดพลาด แต่การแปลของคุณไม่ถูกต้อง;) "Ich habe Durst" = ฉันเป็นคนนี้ "Ich bin neu" = ฉันใหม่ ... ไม่ได้แปลว่าคุณโง่ ... ในกรณีที่คุณกำลังเรียนภาษาเยอรมันจริง ๆ ...
dave_alcarin

@ StéphaneChazelasขอบคุณ แต่ผลลัพธ์ของฉันยังคงมีเพียงหนึ่งไปป์ ...
21940

@dave_alcarin Dank sehr!
ขมวดคิ้ว

คำตอบ:


20

ด้วยPOSIX paste :

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

pasteจะต่อบรรทัดที่สอดคล้องกันของไฟล์อินพุตทั้งหมด ที่นี่เรามีหกไฟล์fileAสี่ไฟล์จากหุ่นในมาตรฐานและ-fileB

รายการตัวคั่นประกอบด้วยช่องว่างสามท่อและช่องว่างในลำดับนั้นจะถูกใช้pasteเป็นวงกลม

สำหรับบรรทัดแรกของหกไฟล์fileAจะถูกตัดแบ่งกับแฟ้มหุ่นครั้งแรก (ซึ่งเป็นอะไรขอขอบคุณไปยังไม่มี-op:ผู้ประกอบการ), line1-fileA<space>การผลิต

แฟ้มหุ่นแรกจะถูกตัดแบ่งกับสองโดยท่อ, การผลิตline1-fileA |แล้วไฟล์ที่สองหุ่นกับแฟ้มหุ่นสามผลิตแฟ้มหุ่นที่สามกับไฟล์มาหุ่นผลิตline1-fileA ||line1-fileA |||

และไฟล์ดัมที่สี่ด้วยfileB, สร้างline1-fileA ||| line1-fileB

ขั้นตอนเหล่านั้นจะถูกทำซ้ำสำหรับทุกบรรทัดให้ผลลัพธ์ที่คาดหวัง


การใช้:|สำหรับการพิมพ์น้อยและส่วนใหญ่ใช้ในเปลือกโต้ตอบ ในสคริปต์คุณควรใช้:

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

เพื่อป้องกัน subshell ไม่ให้เกิดขึ้น


1
+1 :|สำหรับ ฉลาดทางเลือกในการ</dev/null
cas

4
... และ +1 สำหรับการใช้งานอย่างชาญฉลาดของไฟล์ดัมมี่ 4 ไฟล์จากอินพุตมาตรฐานด้วย- - - -แต่ครั้งต่อไปคุณสามารถเขียนคำอธิบายได้สองสามบรรทัด :)
Hastur

thx แต่ฉันยังคงได้รับผลกับหนึ่งท่อ ...
ขมวด

@hui คุณเรียกใช้คำสั่งตามที่กำหนดรวมถึงเครื่องหมายขีดกลางและอักขระเว้นวรรคทั้งหมดหรือไม่ ระบบปฏิบัติการของคุณคืออะไร
Stéphane Chazelas

:|paste -d '|' fileA - - fileBให้รุ่นที่ถูกต้องมากขึ้นโดยไม่มีตัวคั่นช่องว่าง
Pål GD

7

นี่ไม่ใช้ sed, awk หรือ grep แต่คุณสามารถทำได้ง่ายๆในการทุบตี คำสั่งคือ:

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

ปัญหาเกี่ยวกับการวางคือตัวคั่นเป็นอักขระตัวเดียว คุณสามารถแทรกอักขระเดียวและการใช้ sed เพื่อแปลงมันได้ แต่นั่นอาจเป็นข้อผิดพลาดได้ง่ายหากอักขระนั้นปรากฏในไฟล์อินพุตแล้ว


2
โซลูชันของคุณจะไม่ทำงานหากบรรทัดมีอักขระเครื่องหมายทับขวาหรือเริ่มต้นด้วยขีดกลาง คุณต้องการที่จะใช้ก่อนIFS= คุณสามารถทำมันได้ด้วยread pasteดูคำตอบของฉันและยังนี้จะเห็นว่าทำไมควรหลีกเลี่ยงการใช้whileห่วงในสคริปต์เปลือก
cuonglm

มันใช้งานได้กับไฟล์ของฉัน ขอบคุณมาก !!!
ขมวดคิ้ว

5

รุ่น awk (GNU)

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

กับ getlineคำสั่งในawkคุณสามารถตั้งค่า$0(ตัวแปรทั้งหมดสำหรับคอลัมน์) จากบันทึกอินพุตถัดไปหากgetline < "filename"คุณตั้งค่าถัดไป$0จากไฟล์ที่ระบุ

getline <"file" ตั้งค่า $ 0 จากบันทึกไฟล์ครั้งต่อไป; ตั้ง NF


ทำไมความพยายามของคุณไม่ทำงานตามที่คุณคาดหวัง จากที่man pasteเราอ่านได้

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

แต่จะใช้อย่างใดอย่างหนึ่งสำหรับตัวคั่นแต่ละคอลัมน์

ดังนั้นคำสั่ง
paste -d '|*|*' fileA fileB fileA fileBให้เส้นฉันเป็น

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


sedแก้ปัญหาที่ฉันขอแนะนำให้หลีกเลี่ยงการใกล้ชิดแม้ว่าจะพยายามเดิมของคุณเพราะมันแพทช์พฤติกรรมที่ได้รับกับวัตถุประสงค์เดิมของคุณ:

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

เพื่อหลีกเลี่ยงเพราะคุณแทนแต่ละแบบ|ด้วยใหม่|||, แต่คุณต้องคิดว่าสัญลักษณ์ท่อ (| ) ไม่ได้อยู่ในข้อมูลของคุณ , อื่น ๆ ที่คุณต้องจัดการกับกรณีพิเศษและทำให้มีความซับซ้อนมากขึ้นรหัสเพื่อหลีกเลี่ยงผลข้างเคียง


ตัวแปรที่มีโครงสร้างสตริงที่นี่ [ 1 ]<<<

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

คุณตั้งค่าตัวคั่น 5 ตัวด้วย-d ' ||| '(ช่องว่าง, |, |, |, ช่องว่าง) และ 4 ไฟล์จำลอง (- - - - ) ''ที่จะนำข้อมูลจากสตริงที่ว่างเปล่า


ทดสอบกับ GNU Awk 4.0.1, วาง (GNU coreutils) 8.21 และ sed (GNU sed) 4.2.2


ขอบคุณคำสั่ง awk ใช้งานได้!
ขมวดคิ้ว

1
ยินดีต้อนรับ. อัปเดตคำตอบแล้วเพิ่มsedตัวอย่างเพื่อหลีกเลี่ยง (:-)) และความคิดเห็นเพิ่มเติม
Hastur

4

หากคุณต้องการหลีกเลี่ยงเวทย์มนตร์และดราม่าของไฟล์ตัวคั่นแบบวงกลมและไฟล์จำลองคุณสามารถผนวกตัวคั่นของคุณไปที่ไฟล์เดียวก่อนที่จะวางพวกเขา:

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

จะช่วยให้

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.

ฉันชอบสิ่งนี้เพื่อความเรียบง่าย ฉันเชื่อว่าคุณหมายถึง "prepend" ไม่ใช่ "ผนวก" แม้ว่า คำตอบ awk ของ Checkout Hastur สำหรับรุ่น awk ของสิ่งนี้
Wildcard

คุณควรเปลี่ยนการทดแทนกระบวนการเป็นไพพ์ดังนั้นคุณจะไม่มีขีด จำกัด สำหรับจำนวนเชลล์ที่สนับสนุน
cuonglm

@ Wildcard ใช่, prepend แต่ฉันจะเขียนมันใหม่เพื่อผนวกเข้ากับ filea ฉันคิดว่า awk ค่อนข้างเกินความสามารถสำหรับเรื่องนี้
58

@cuonglm จริง แต่ฉันต้องการหลีกเลี่ยงท่อเพื่อความชัดเจน ผมรู้สึกว่าท่อจะทำให้มันเริ่มที่จะมีลักษณะเช่นไฟล์หุ่น แต่คุณถูกต้อง
snth

0

คุณสามารถทำได้ในไพ ธ อนด้วยวิธีนี้

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.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.