非常に長い行での検索と置換のSed代替


9

レコードの最後に改行を入れなかったプログラムによって生成されたファイルがあります。レコード間に改行を入れたいのですが、簡単なsedスクリプトでそれを行うことができます。

sed -e 's/}{/}\n{/g'

問題は、入力ファイルのサイズが数ギガバイトであるため、sedへの入力行の長さが数GBであることです。sedはメモリに行を保持しようとしますが、この場合は機能しません。私は--unbufferedオプションを試しましたが、それはそれが遅くなるようで、正しく終了することを許可しませんでした。


サンプル入力ファイルをどこかにアップロードして、アイデアを試すことはできますか?
mkc 2015年

3
最初にを使用trしてに翻訳}\n、次に各行の終わりにsedを追加するために使用でき}ますか?このように:tr '}' '\n' < your_file.txt| sed 's/$/}/'
user43791

ファイルの最後に改行を追加すると、役に立ちますか?例:printf "\n" >> file
nanny

1
@Ketan、私は78のガベージ文字でファイルを書き込み、その後}{数ギガバイトになるまで繰り返し続ければ十分だと思います。
ナニー

@nanny-良い点-しかし、78はどこで手に入りますか?レコードが既にブロックされている場合は、それdd if=file cbs=80 conv=unblockを実行しますが、それほど簡単ではありません。
mikeserv 2015年

回答:


7

入力レコード区切り文字を設定できる別のツールを使用できます。例えば

  • Perl

    perl -pe 'BEGIN{ $/="}{" } s/}{/}\n{/g' file
    

    特殊変数$/は入力レコードセパレータです。に設定すると}{、行がで終わるように定義され}{ます。そうすれば、全部をメモリに読み込まなくても、望みどおりの結果を得ることができます。

  • mawkまたはgawk

    awk -v RS="}{" -vORS= 'NR > 1 {print "}\n{"}; {print}' file 
    

    これは同じ考えです。RS="}{"レコードセパレーターをに設定してから、改行(最初のレコードを除く)と現在のレコード}{を印刷}します{


3

Perlが救い出します:

perl -i~ -e ' $/ = \1024;
              while (<>) {
                  print "\n" if $closing and /^{/;
                  undef $closing;
                  s/}{/}\n{/g;
                  print;
                  $closing = 1 if /}$/;
              } ' input1 input2

に設定$/する\1024と、1024バイトのチャンクでファイルが読み取られます。$closing可変ハンドルケースときチャンク端で}、次のいずれかで始まります{


1
+1、おそらく最良の解決策。他のperl / awkソリューションも正常に機能しますが、約17GBに相当する文字の後に最初のレコード区切り文字が発生した場合はどうなりますか?
don_crissti 2015年

2

やったほうがいい:

{ <infile tr \} \\n;echo {; } | paste -d'}\n' - /dev/null >outfile

これはおそらく最も効率的なソリューションです。

これにより、{}後続のデータを保護することができます。もう1つのtrプロセスを使用して、それを入れ替えて、最初の{フィールドの先頭で空白行を実行できます。お気に入り...

tr {} '}\n'| paste -d{\\0 /dev/null - | tr {}\\n \\n{}

したがって、最初の例では、donのサンプルデータを使用します。

printf '{one}{two}{three}{four}' |
{ tr \} \\n; echo {; }           |
paste -d'}\n' - /dev/null
{one}
{two}
{three}
{four}
{}

... 2つ目は...

printf '{one}{two}{three}{four}'      |
tr {} '}\n'| paste -d{\\0 /dev/null - |
tr {}\\n \\n{}
#leading blank
{one}
{two}
{three}
{four}

2番目の例の末尾の改行はありません-最初の例はありますが。


0

sed呼ばれるバイナリのようなユーティリティbbe

この場合、sedのような構文を使用するのが最も簡単です。

私はずっと使って好みbbe(あなたの{ユニ、linu} Xのパッケージのインストール、EQを経由して利用できるユーティリティapt-get)。または、あなたがgitの群衆の1人である場合は、ここで特定のリンクを個人的に検証していません。

1. s/before/after/イディオムをサポートします

これは「バイナリブロックエディタ」であり、sedのような(他の)操作をサポートします。これには、s/before/after/必要な非常に一般的な置換イディオムが含まれます。bbeの観点から見れば行自体はないため、コマンドの最後に「グローバルg」はありません。

簡単なテストとして(必須に注意してください-e):

$ echo hello | bbe -e 's/l/(replaced)/'

生成する:

he(replaced)(replaced)o

あなたの特定のケースで2 }{}\n{の変換

我々は(例えば)形式で百万の数字で満たされ、大規模なファイルを持っていたのであれば{1}{2}{3}... {1000000}なしキャリッジリターンで、我々は交換することができ}{}\n{簡単に、そしてすべての数字を1行に1つずつ持っています。

これはbbe次のコマンドを使用します。

bbe -e 's/}{/}\n{/'

このzshループでテストしたとおり、次のコードの末尾のみを取得します。

$ for ((num=0; num<1000000; num++)) do; echo -n "{$num}"; done | bbe -e 's/}{/}\n{/' | tail

これは次のようになります。

{999990}
{999991}
{999992}
{999993}
{999994}
{999995}
{999996}
{999997}
{999998}
{999999}

(もちろん、後続のキャリッジリターンはありません。)

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