リストを区切り文字付きの単一行に変換します


16

私は、この形式のIPアドレスのリスト(負荷)を取らなければなりません。

 134.27.128.0
 111.245.48.0
 109.21.244.0

(IPが構成された)で、間のパイプと、この形式に変えます

134.27.128.0 | 111.245.48.0 | 109.21.244.0 | 103.22.200.0/22

私はそれを見つけると思いなどのコマンドを置き換えるsedが、私はそれを動作させることはできません。


3
tr改行を|パイプにまとめるだけですか?好き<ipfile tr \\n \| >outfile
mikeserv

周辺のスペースは|必要ですか?
クオンルム

2
@uselesslinuxman-いいえ。入力リダイレクトが必要<です。だから<mydoc tr \\n \| >mydoc2。しかし、それではスペースが得られません。それらの場合、おそらく最も迅速な解決策はpaste -d' | ' mydoc /dev/null /dev/null >mydoc2
-mikeserv

1
@mikeserv:うまくいかないと思う。paste各ファイルから対応する行を書き込みます。なし-sでは、ファイルにある行数を取得します。
-cuonglm

回答:


15

有名なSed One-Liners Explained、Part I:に基づくsedの使用:39.バックスラッシュ「\」で終わる場合、次の行を追加します(ここではバックスラッシュに関する部分を無視し、\n改行を必要な|セパレータ):

sed -e :a -e '$!N; s/\n/ | /; ta' mydoc > mydoc2

生産する必要があります mydoc2

134.27.128.0 |  111.245.48.0 |  109.21.244.0

@don_crisstiごめんなさい、それはタイプだった-修正、ありがとう
-steeldriver

残念ながら、これは実際には実際には機能しません。少なくとも、無制限のストリーム用ではありません。これを行うと、あなたはライン時間、あなたの入力の全体を飲み込むために持っていて、それをすべて消化するまで出力することであっても1バイトを書き込むことはできません-それがすべて1行に変身します。それは扱いにくく、セグメンテーション違反になりやすいです。
mikeserv

100万個のIPは16M未満です。ここで制限を解除するには、非常に大きなリストが必要です。eof検出に検索を使用すると、入力ファイルサイズでO(N ^ 2)が実行されるため、より問題が生じます。 sed 'H;1h;$!d;x;s/\n/ | /g'線形です。
jthill

@jthill - POSIXは保証sed8Kのパターンスペースを。それは16M未満です。
mikeserv

9

私は、これらのいくつか(+いくつかの選択肢)が、かなり大きなファイル(163MiBIP行ごとに1つ、約1,300万行)でどのように速度的に機能するかを知りたいと思いました。

wc -l < iplist
13144256

結果(sync; echo 3 > /proc/sys/vm/drop_caches各コマンドの後、数時間後にテストを逆の順序で繰り返しましたが、違いは無視できました。また、使用していることに注意してくださいgnu sed):

steeldriver
非常に遅い。待機中の2分後に中止されていない...ので、この1には結果。

クオンルム

awk 'FNR!=1{print l}{l=$0};END{ORS="";print l}' ORS=' | ' iplist

real    0m3.672s

perl -pe 's/\n/ | / unless eof' iplist

real    0m12.444s

mikeserv

paste -d\  /dev/null iplist /dev/null | paste -sd\| - 

real    0m0.983s

jthill

sed 'H;1h;$!d;x;s/\n/ | /g' iplist

real    0m4.903s

アビナッシュ・ラジ

time python2.7 -c'
import sys
with open(sys.argv[1]) as f:
    print " | ".join(line.strip() for line in f)' iplist

real    0m3.434s

そして

val0x00ff

while read -r ip; do printf '%s | ' "$ip"; done < iplist

real    3m4.321s

つまり 184.321sます。当然のことながら、これは200倍よりも遅いですmikeservのソリューション。



awkを使用する他の方法は次のとおりです。

awk '$1=$1' RS= OFS=' | ' iplist

real    0m4.543s

awk '{printf "%s%s",sep,$0,sep=" | "} END {print ""}' iplist

real    0m5.511s

perl:

perl -ple '$\=eof()?"\n":" | "' iplist

real    0m9.646s

xargs:

xargs <iplist printf ' | %s' | cut -c4-

real    0m6.326s

head + paste + tr + catの組み合わせ:

{ head -n -1 | paste -d' |' - /dev/null /dev/null | tr \\n \ ; cat ; } <iplist

real    0m0.991s

あなたが持っている場合GNU coreutilsやIPアドレスのリストが本当に巨大でない場合(のは50000個のIPアドレスまで言わせて)あなたもでこれを行うことができますpr

pr -$(wc -l infile) -tJS' | ' -W1000000 infile >outfile

どこ

-$(wc -l infile)         # no. of columns (= with no. of lines in your file)
-t                       # omit page headers and trailers
-J                       # merge lines
-S' | '                  # separate columns by STRING
-W1000000                # set page width

たとえば、6行のファイルの場合:

134.28.128.0
111.245.28.0
109.245.24.0
128.27.88.0
122.245.48.0
103.44.204.0

コマンド:

pr -$(wc -l <infile) -tJS' | ' -W1000 infile

出力:

134.28.128.0 | 111.245.28.0 | 109.245.24.0 | 128.27.88.0 | 122.245.48.0 | 103.44.204.0

don- while ... readループの@ val0x00ffによる質問の提案を追加してもらえますか?163k read()write()callがベンチマークで何に変換されるかを知りたいです。道グレート答え、。
mikeserv

1
@mikeserv-問題ありません、私はそれをします(しかし、本当に遅くなります)。
-don_crissti

それは本当にクールなリンクです。私は特に、著者が同様の6年前のベンチマークへのリンクも提供していることを気に入っています。あなたは予告行いsed、その時点でその地位を向上させているようだ(とその正規表現エンジンにおそらく唯一の非常にいくつかの変更があったが)が、grep劇的に性能が遅れているようだ(特に長い行のための)?かしらperlそのエンジンへの追加は、それらの結果上の任意のベアリングを持っている...それはそれもきちんとだdashではありませんひどいですbashここではそうワット/共通はるかに遅いだろうIFS=前に追加。
mikeserv

うーん...そのリンクは、私が本当にCを習得し、最終的にlex適切に使い始めることができるようにするために本当に必要な別の強力な指標です。
mikeserv

8

あなたは使用することができますAWK

awk 'FNR!=1{print l}{l=$0};END{ORS="";print l}' ORS=' | ' file > new_file

ORS=' | '設定された出力レコードセパレータをする' | '代わりに、改行の。

またはインプレースでの編集perl

perl -pe 's/\n/ | / unless eof' file

ありがとう。私がどれだけ学んだpaste作品。大変感謝いたします。
mikeserv

@mikeserv:どういたしまして。don_crisstiがベンチマークで示したように、pasteソリューションは最速です。
クオンルム

出力は改行で終わっていません。ブロックORS=""内で置き換える必要があるかもしれません。ENDORS="\n"
phk

4

だから私はすべてが間違っていました-そしてこの質問は私に多くを教えてくれましたpaste。cuonglmが正しく指摘しているように、erialのpasteinファイルでない限り-s、常に\n、infileリストの最後のewlineが出力に追加され、それが書き込まれたときに出力に追加されます。私は、paste -s振る舞いがデフォルトのモードであると信じていました-これは誤解であり、明らかbusybox pasteに喜んで補強できました。次のコマンドは、アドバタイズされたw /として機能しますbusybox

paste -d'|  ' - - infile </dev/null >outfile

ただし、仕様どおりには機能しません。正しく実装されたpaste場合でも、\n書き込まれた各シーケンスに末尾のewline が追加されます。それでも、それはすべての後に大したことありません。

paste -d\  - infile - </dev/null | paste -sd\| - >outfile

@don_crissti-ダンギット。愚かなタブレット。明らかなことは、2つのペーストです。
mikeserv

1
まあ、pr念頭に置いていたが、どうやらそれは巨大な入力ファイルで蒸気が枯渇するので、実際に速度をテストすることはできなかったが、妥当な長さのファイルでは問題なく動作する。あなたの解決策は群を抜いて最速です(驚きpasteはありません- 非常に高速です)、私の投稿を参照してください。
-don_crissti

3

活用するvim

vim -n -u NONE -c '1,$-1s/\n/ | /g|wq!' data

説明:

-n スワップファイルを無効にする

-u NONE すべての初期化をスキップするために使用されます。

-c {command} ファイルが読み込まれた後にコマンドを実行します。

1,$-1s/\n/ | /g範囲はs/\n/ | /g(改行をスペースパイプスペースで置き換える)1,$-1s( - 1最後の行まで1行目)

wq! 強制的に書き込み、終了


注意:

ファイルの実際の大きさによっては、これは悪い考えかもしれません。


1
基本的にこれらのコマンドのほぼすべてが私が達成する必要があるもののために機能するので、すべてに感謝します。(いつ)行き詰まったら、今どこに来るべきかを知っています。ありがとう
uselesslinuxman

3

trとsedを使用したワンライナー:

cat file | tr '\n' '|' | sed 's/||$/\n/'
134.27.128.0|111.245.48.0|109.21.244.0

2つの後続パイプを削除する理由 入力が空白行(2つの改行)で終了した場合、最後に2のみがあります。
JigglyNaga

2

Python経由。

$ python -c '
import sys
with open(sys.argv[1]) as f:
    print " | ".join(line.strip() for line in f)' file

前のスペースprintは非常に重要でした。


2

ここに使用する別のものがあります xxd

xxd -c1 -ps data | sed '$!s/0a/207c20/' | xxd -r -ps

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.