複数列のテキストファイルを処理して別の複数列のテキストファイルを取得する方法


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

または、次のような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  jj

私はawkソリューションを取得することを好みますが、他のソリューションも歓迎します。

回答:


1

また、GNU awkを1回呼び出すだけで実行できます。

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:はい、使用する方が安全"%s", ...です。更新
トール

確認いただきありがとうございます。:) awkところで、この質問に対する他の回答のコマンドにも同じことが当てはまります。
ワイルドカード

20

各フィールドを1行に入れて、ポストカラム化します。

1行の各フィールド

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

円柱状

ペースト

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

... | 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回線を呼び出すべきではありませんechoprintf
ワイルドカード

1
@Wildcard:デフォルトでxargs呼び出し/bin/echo
トール

1
うわー、私にはわからなかった!POSIXでも指定されています。ありがとう!
ワイルドカード

@Wildcard:それにデータを送信するとxargs/bin/echo問題を引き起こすオプションのように見えます...警告を追加しました。
トール

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が指摘したように、これはファイルが適切にフォーマットされている場合にのみ機能します。シェルがグロブとして解釈する特殊文字がなく、デフォルトの単語分割規則に満足しているからです。ファイルがそのテストに「合格」するかどうかについて質問がある場合は、このアプローチを使用しないでください。

1つの可能性は、printfそれを次のように行うことです

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

これは、コンテンツの単語分割を行い、your_fileそれらをペアにして、間にタブを入れて印刷します。でより多くの%sフォーマット文字列を使用して、printf列を追加することができます。


1
これは、特殊文字を含まないファイルに依存します。たとえば、アスタリスク(*)がある場合、非常に予期しない結果が得られます。
ワイルドカード

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

(4を列の数で置き換えます)


4

BSD rs(変形)ユーティリティ:

$ 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スクリプトアプローチ。

ここでの基本的な考え方は、テキスト内のすべての単語を1つのリストにフラット化し、2番目のアイテムごとに改行を印刷することです(2つの列に列を入れるためです)。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

3列バージョン(上記のように、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.