Başka bir çok sütunlu metin dosyası almak için çok sütunlu bir metin dosyası nasıl işlenir?


17

Bir metin dosyam var:

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

Nasıl işleyebilir ve böyle bir 2 sütun dosyası alabilirsiniz:

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

Veya bunun gibi üç sütunlu bir dosya:

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 çözümü almayı tercih ederim ama diğer çözümler de memnuniyetle karşılıyor.

Yanıtlar:


1

Tek bir GNU awk çağrısı ile de yapabilirsiniz:

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"
}

Bu şekilde çalıştırın:

awk -f reshape.awk n=2 infile

Veya tek astar olarak:

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

Çıktı:

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

Veya 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

Bu $1, biçim dizesi olarak kullanılmaz printfmı?
Wildcard

@Wildcard: Doğru, kullanımı daha güvenlidir "%s", .... Güncellendi
Thor

Onayladığınız için teşekkürler. :) Aynı şey awkbu soruya verilen diğer cevabınızdaki komut için de geçerlidir .
Wildcard

20

Her alanı bir satıra koyun ve sütun sonrasına koyun.

Bir satırdaki her alan

tr

tr -s ' ' '\n' < infile

grep

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

sed

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

veya daha fazla taşınabilir:

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

awk

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

veya

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

Columnate

yapıştırmak

2 sütun için:

... | paste - -

3 sütun için:

... | paste - - -

vb.

sed

2 sütun için:

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

3 sütun için:

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

vb.

xargs

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

Gibi xargskullanımlar /bin/echoyazdırmak için, seçenekleri gibi görünüyor bu verileri dikkat echogibi yorumlanır.

awk

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

pr

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

veya

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

sütunlar (otojen paketinden)

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

Tipik çıktı:

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
Smaç. +1 efendim
Steven Penny

Olmamalıdır xargshat görüşmesi echoya printf?
Wildcard

1
@Wildcard: varsayılan olarak xargsaramalar/bin/echo
Thor

1
Vay, hiçbir fikrim yoktu! POSIX tarafından bile belirtilir . Teşekkürler!
Wildcard

@Wildcard: Veri gönderme , sorunlara neden olan xargsseçeneklere benziyor /bin/echo... Bir uyarı ekledim.
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

Wildcard'ın işaret ettiği gibi, bu yalnızca dosyanız güzel bir şekilde biçimlendirilmişse çalışır, çünkü kabuğun glob olarak yorumlayacağı herhangi bir özel karakter yoktur ve varsayılan kelime bölme kurallarından memnun kalırsınız. Dosyalarınızın bu testi "geçip geçmeyeceği" konusunda herhangi bir sorunuz varsa, bu yaklaşımı kullanmayın.

Bir olasılık bunu printfyapmak için kullanmak olacaktır

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

Bu, içeriğinde kelime bölme yapar your_fileve bunları eşleştirir ve aradaki sekmelerle yazdırır. Ek sütunlara sahip olmak için %siçinde daha fazla biçim dizesi kullanabilirsiniz printf.


1
Özel karakter içermeyen dosyaya bağlıdır. Örneğin, herhangi bir yıldız işareti (*) varsa, çok beklenmedik sonuçlar alırsınız.
Wildcard

4
perl -n0E 'say s/\s+/ ++$n % 4 ?"\t":"\n"/gre' file

(4'ü sütun sayısı ile değiştirin)


4

BSD rs(yeniden şekillendirme) yardımcı programı:

$ 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 2olduğu satırlar ve sütunlar . Belirtme 0"satırları sütunlardan otomatik olarak hesapla" anlamına gelir.


3

Python komut dosyası yaklaşımı.

Buradaki temel fikir, metninizdeki tüm kelimeleri bir listeye düzleştirmek ve daha sonra her ikinci öğeden sonra yeni satır yazdırmaktır (bu, iki sütuna sütun oluşturmak içindir). Eğer 3 sütun, değişiklik istiyorsanız index%2içinindex%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 = []

Örnek çıktı:

$ 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

Üç sütunlu sürüm (yukarıda belirtildiği gibi, yalnızca index%3 == 0değişti)

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