จะประมวลผลไฟล์ข้อความแบบหลายคอลัมน์เพื่อรับไฟล์ข้อความแบบหลายคอลัมน์ได้อย่างไร


17

ฉันมีไฟล์ข้อความ:

a   aa  aaa     b   bb  bbb     c   cc  ccc
d   dd  ddd     e   ee  eee     f   ff  fff
g   gg  ggg     h   hh  hhh     i   ii  iii
j   jj  jjj

ฉันจะประมวลผลและรับไฟล์คอลัมน์ 2 แบบนี้ได้อย่างไร:

a   aa
aaa b
bb  bbb
c   cc
ccc d
dd  ddd
e   ee
eee f
ff  fff
g   gg
ggg h
hh  hhh
i   ii
iii j
jj  jjj

หรือไฟล์สามคอลัมน์เช่นนี้

a   aa  aaa
b   bb  bbb
c   cc  ccc
d   dd  ddd
e   ee  eee
f   ff  fff
g   gg  ggg
h   hh  hhh
i   ii  iii
j   jj  jj

ฉันชอบที่จะได้รับการแก้ปัญหา awk แต่ยินดีที่จะแก้ปัญหาอื่น ๆ

คำตอบ:


1

คุณสามารถทำได้ด้วยการร้องขอ GNU awk เพียงครั้งเดียว:

reshape.awk

# Set awk to split input at whitespace characters and
# use tab as the output field separator 
BEGIN {
  RS="[ \t\n]+"
  OFS="\t"
}

# Print using OFS or ORS based on the element index
{
  printf "%s", $1 (NR%n == 0 ? ORS : OFS)
}

# Append a missing new-line when last row is not full
END { 
  if( NR%n != 0) 
    printf "\n"
}

เรียกใช้เช่นนี้:

awk -f reshape.awk n=2 infile

หรือเป็นหนึ่งซับ:

awk -v n=2 'BEGIN { RS="[ \t\n]+"; OFS="\t" } { printf "%s", $1 (NR%n == 0 ? ORS : OFS) } END { if( NR%n != 0) printf "\n" }' infile

เอาท์พุท:

a   aa
aaa b
bb  bbb
c   cc
ccc d
dd  ddd
e   ee
eee f
ff  fff
g   gg
ggg h
hh  hhh
i   ii
iii j
jj  jjj

หรือด้วยn=3:

a   aa  aaa
b   bb  bbb
c   cc  ccc
d   dd  ddd
e   ee  eee
f   ff  fff
g   gg  ggg
h   hh  hhh
i   ii  iii
j   jj  jjj

สิ่งนี้ไม่ใช้$1เป็นสตริงรูปแบบprintfใช่หรือไม่
Wildcard

@Wildcard: "%s", ...ใช่มันเป็นที่ปลอดภัยในการใช้งาน อัปเดต
Thor

ขอบคุณสำหรับการยืนยัน :) เช่นเดียวกับawkคำสั่งในคำตอบอื่น ๆ ของคุณกับคำถามนี้โดยวิธี
Wildcard

20

วางแต่ละฟิลด์ในบรรทัดและโพสต์คอลัมน์

แต่ละฟิลด์ในหนึ่งบรรทัด

TR

tr -s ' ' '\n' < infile

grep

grep -o '[[:alnum:]]*' infile

sed

sed 's/\s\+/\n/g' infile

หรือมากกว่าพกพา:

sed 's/\s\+/\
/g' infile

awk

awk '$1=$1' OFS='\n' infile

หรือ

awk -v OFS='\n' '$1=$1' infile

Columnate

วาง

สำหรับ 2 คอลัมน์:

... | paste - -

สำหรับ 3 คอลัมน์:

... | paste - - -

เป็นต้น

sed

สำหรับ 2 คอลัมน์:

... | sed 'N; s/\n/\t/g'

สำหรับ 3 คอลัมน์:

... | sed 'N; N; s/\n/\t/g'

เป็นต้น

xargs

... | xargs -n number-of-desired-columns

ในฐานะที่xargsใช้/bin/echoในการพิมพ์ระวังว่าข้อมูลที่มีลักษณะเหมือนตัวเลือกในการechoจะถูกตีความว่าเป็นเช่นนั้น

awk

... | awk '{ printf "%s", $0 (NR%n==0?ORS:OFS) }' n=number-of-desired-columns OFS='\t'

ราคา

... | pr -at -number-of-desired-columns

หรือ

... | pr -at -s$'\t' -number-of-desired-columns

คอลัมน์ (จากแพ็คเกจ autogen)

... | columns -c number-of-desired-columns

เอาท์พุททั่วไป:

a   aa  aaa
b   bb  bbb
c   cc  ccc
d   dd  ddd
e   ee  eee
f   ff  fff
g   gg  ggg
h   hh  hhh
i   ii  iii
j   jj  jjj

2
สแลมดังค์ +1 คุณ
สตีเวนเพนนี

ไม่ควรxargsโทรสายechoหรือprintf?
Wildcard

1
@Wildcard: การxargsโทร/bin/echoตามค่าเริ่มต้น
Thor

1
ว้าวฉันไม่รู้เลย! ก็จะยิ่งระบุโดย POSIX ขอบคุณ!
Wildcard

@Wildcard: กำลังส่งข้อมูลไปยังxargsตัวเลือกที่/bin/echoทำให้เกิดปัญหา ... ฉันได้เพิ่มคำเตือน
Thor

9
$ sed -E 's/\s+/\n/g' ip.txt | paste - -
a   aa
aaa b
bb  bbb
c   cc
ccc d
dd  ddd
e   ee
eee f
ff  fff
g   gg
ggg h
hh  hhh
i   ii
iii j
jj  jjj

$ sed -E 's/\s+/\n/g' ip.txt | paste - - -
a   aa  aaa
b   bb  bbb
c   cc  ccc
d   dd  ddd
e   ee  eee
f   ff  fff
g   gg  ggg
h   hh  hhh
i   ii  iii
j   jj  jjj

9

ตามที่ไวลด์การ์ดชี้ให้เห็นสิ่งนี้จะใช้ได้ก็ต่อเมื่อไฟล์ของคุณมีการจัดรูปแบบเป็นอย่างดีโดยที่ไม่มีอักขระพิเศษใด ๆ ที่เชลล์จะตีความเป็น globs และคุณมีความสุขกับกฎการแยกคำเริ่มต้น หากมีคำถามใด ๆ เกี่ยวกับว่าไฟล์ของคุณจะ "ผ่าน" การทดสอบนั้นหรือไม่อย่าใช้วิธีนี้

ความเป็นไปได้อย่างหนึ่งก็คือใช้printfทำเช่นนั้น

printf '%s\t%s\n' $(cat your_file)

ที่จะทำการแยกคำในเนื้อหาของyour_fileและจะจับคู่พวกเขาและพิมพ์ด้วยแท็บในระหว่าง คุณสามารถใช้%sสตริงรูปแบบเพิ่มเติมในการที่printfจะมีคอลัมน์พิเศษ


1
ขึ้นอยู่กับไฟล์ที่ไม่มีตัวอักษรพิเศษ ตัวอย่างเช่นถ้ามีเครื่องหมายดอกจัน (*) ใด ๆ คุณจะได้รับผลลัพธ์ที่ไม่คาดคิดมาก
Wildcard


4

rsยูทิลิตี้BSD (ปรับรูปร่าง):

$ rs 0 2
a   aa  aaa     b   bb  bbb     c   cc  ccc
d   dd  ddd     e   ee  eee     f   ff  fff
g   gg  ggg     h   hh  hhh     i   ii  iii
j   jj  jjj
[Ctrl-D][Enter]
a    aa
aaa  b
bb   bbb
c    cc
ccc  d
dd   ddd
e    ee
eee  f
ff   fff
g    gg
ggg  h
hh   hhh
i    ii
iii  j
jj   jjj

0 2เป็นแถวและคอลัมน์ การระบุ0หมายถึง "คำนวณแถวโดยอัตโนมัติจากคอลัมน์"


3

วิธีการสคริปต์ Python

แนวคิดพื้นฐานที่นี่คือการทำให้คำทั้งหมดในข้อความของคุณเรียบเป็นหนึ่งรายการจากนั้นพิมพ์บรรทัดใหม่หลังจากแต่ละรายการที่สอง (สำหรับการจัดเรียงคอลัมน์ในสองคอลัมน์) หากคุณต้องการ 3 คอลัมน์เปลี่ยนindex%2เป็นindex%3

#!/usr/bin/env python3
import sys

items = [i for l in sys.stdin 
           for i in l.strip().split()]
line = []
for index,item in enumerate(items,1):
    line.append(item)
    if index%2 == 0:
       print("\t".join(line))
       line = []

ตัวอย่างผลลัพธ์:

$ python recolumnate.py < input.txt                                            
a   aa
aaa b
bb  bbb
c   cc
ccc d
dd  ddd
e   ee
eee f
ff  fff
g   gg
ggg h
hh  hhh
i   ii
iii j
jj  jjj

รุ่นสามคอลัมน์ (ดังที่ได้กล่าวไว้ข้างต้นมีการindex%3 == 0เปลี่ยนแปลงเท่านั้น)

$ cat recolumnate.py                                                           
#!/usr/bin/env python3
import sys

items = [i for l in sys.stdin 
           for i in l.strip().split()]
line = []
for index,item in enumerate(items,1):
    line.append(item)
    if index%3 == 0:
       print("\t".join(line))
       line = []

$ python recolumnate.py < input.txt                                            
a   aa  aaa
b   bb  bbb
c   cc  ccc
d   dd  ddd
e   ee  eee
f   ff  fff
g   gg  ggg
h   hh  hhh
i   ii  iii
j   jj  jjj
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.