sed は、1 つのコマンドで複数の項目を削除してデータを削除します。

sed は、1 つのコマンドで複数の項目を削除してデータを削除します。

sedのコマンドを使用して、次のメールを削除していますhotmail。同時に複数の項目を確認できますか?list.txt(1行に1つの項目)から読み込むことをお勧めします。

sed -i '/^[^,]*,[^,]*hotmail/Id' data.txt

.txtでロードできない場合は、次の方法がありますか?hotmail|gmail|yahoo

data.txtライン例:

"foxva****omes****","[email protected]","8*** Rd","Ne***ah","Wi***in","54***","*******"
"foxva****omes****","[email protected]","8*** Rd","Ne***ah","Wi***in","54***","*******"
"foxva****omes****","[email protected]","8*** Rd","Ne***ah","Wi***in","54***","*******"

答え1

sedファイルをスクリプトとしてフォーマットできる場合、sedこれは自動的に実行できます。以下はGNUで動作しますsed。 BSDの場合、sed2回目の呼び出しはうまくいきます...-i '' -esed

sed -ne's|[]\*&^.$/[]|\\&|g' \
     -e's|..*|/^@&",/d|p' <./list.txt |
sed -ie'h;s/[^,]*[^@]*//' -f- -eg ./data.txt

これで...

-e's|..*|/^@&",/Id|p' ...

...2行目では、GNUは一致するものをすべて削除sedします。dlist.txt大文字と小文字は区別されませんが、他のほとんどの構文エラーと同じです。

各行に対して実行されるスクリプトの先頭にある 2 番目のフィールドの 1 番目のフィールドと@1 番目のフィールドより前のすべての項目と 1 番目のフィールドを削除して一致を絞り込み、一致確認を実行し、行がすべての一致を通過すると、etsはAを保存します。前のスペースのスクリプトの上部にある行のコピーですghこれにより、ゲームごとにこれを行うsed必要がなくなります。/^[^,]*,[^,]*.../もしlist.txt時間がかかっても決して速いプロセスではないでしょう。grep -Fこの場合、優先する必要があります(おそらくこの場合)


sed両方grep できるパフォーマンスの向上 - ほとんどの場合確かにしたがって - 使用される文字セットのサイズが小さくなった場合。たとえば、現在UTF-8ロケールにある場合は、次のようにします。

(   export LC_ALL=C
    sed -ne's|[]\*&^.$/[]|\\&|g' \
         -e's|..*|/^@&",/Id|p'   |
    sed -ie'h;s/[^,]*[^@]*//' -f-\
         -eg ./data.txt
)   <./list.txt

...正規表現エンジンは、一致のために数万の異なる文字を考慮する必要はなく、128の可能性のみを考慮するので、世界を変えることができます。いかなる方法でも結果に影響を与えてはいけません。各文字はCロケールのバイトであり、すべての文字が適切に考慮されます。

sed -iこれは最良の状況では信頼できるスイッチではないため、可能であれば避けるべきです。


これを行うには、次を使用します。grep そして sed -i:

(   export LC_ALL=C
    cut -d\" -f4 | cut -d@ -f2    |
    grep -Fixnf ./list.txt        |
    sed -e's|:*\([0-9]*\).*|:\1|p'\
        -e's||\1!{p;n;b\1|p'      \
        -e's||};n|'               |
    sed -nif- -e:n -e'p;n;bn'     \
        ./data.txt
)   <./data.txt

sedこれが私が想像できる最速の方法です-i。分析方法は次のとおりです。

  1. cut | cut

    • 最初の2つは入力ラインを次のようにcut減らします。./data.txt

     "foxva****omes****","[email protected]","8*** Rd","Ne***ah","Wi***in","54***","*******"
    

    hotmail.com
    
  2. grep

    • grepその後、この入力をパターンファイルの各行-fと比較できます。list.txt-i大文字と小文字を区別しない-F固定文字列を使用して行全体を照合し、出力の各行の先頭に行番号を-x報告します。-n
  3. sed -e

    • sed出力を行番号で削除し、以下のようにgrep別のスクリプトを作成します。sedgrepライン10と20が一致すると仮定):

     :10
     10!{p;n;b10
     };n
     :20
     20!{p;n;b20
     };n
    
  4. sed -inf-

    • 最後はstdinをスクリプトとしてsed読み、一度だけ実行します。通常、スクリプトのように、各入力行に対してスクリプトを逆追跡して実行するのではなく、代わりに-最初で唯一の作業時にスクリプトを実行します。sed入力 - それだけ対応するテストは、各入力ラインに対して一度だけ試みるべきです。

    • 前の例では、行1から9はsed次のことを行います。

      • 現在の行が最初の行ではない場合は、現在の行を!印刷10{てそれを追加の入力行で上書きし、名前付きラベルに逆追跡します。pnb:10
    • 最後の行が印刷sedされますp。次に、現在の行をextで上書きし、nすべての入力が使用されるまでラベルをb貼り付けます。:n


次の場合は機能しません。./data.txtとても大きいです。sedスクリプトが確実に処理できるよりもはるかに大きい入力ファイルを処理しようとすると、スクリプトが輻輳するためです。この問題に対する解決策は、入力をチャンクに取り込むことです。これできる正しい種類のリーダーを使用すると、パイプラインでもこれを確実に実行できます。dd正しい種類の読者です。

次のテストファイルを作成しました。

sh -c ' _1=\"foxva****omes****\",\"scott@
        _2='\''","8*** Rd","Ne***ah","Wi***in","54***","*******"'\''
        n=0
        for m do printf "$_1%s$_2\n$_1$((n+=1))not_free.com$_2\n" "$m"
        done
'       $(cat ~/Downloads/list.txt) >/tmp/data.txt

...どこlist.txt持っているここあなたの言葉によるとその他の問題。それは次のように動作します...他のすべての行について...

"foxva****omes****","[email protected]","8*** Rd","Ne***ah","Wi***in","54***","*******"
"foxva****omes****","scott@1not_free.com","8*** Rd","Ne***ah","Wi***in","54***","*******"
"foxva****omes****","[email protected]","8*** Rd","Ne***ah","Wi***in","54***","*******"
"foxva****omes****","scott@2not_free.com","8*** Rd","Ne***ah","Wi***in","54***","*******"

それから80mbsを少し増やしました。

while [ "$(($(wc -c <data.txt)/1024/1024))" -lt 80 ]
do    cat <<IN >./data.txt
$(    cat ./data.txt ./data.txt)
IN
done
ls -hl ./data.txt
wc -l <./data.txt

-rw-r--r-- 1 mikeserv mikeserv 81M Jul 19 22:22 ./data.txt
925952

...それから私は...

(   trap rm\ data.tmp 0;  export  LC_ALL=C
    <./data.txt dd bs=64k cbs=512 conv=block    |
    while       dd bs=64k cbs=512 conv=unblock  \
                count=24  of=./data.tmp
                [ -s ./data.tmp ]
    do          
    <./data.tmp cut -d\" -f4 |  cut -d@  -f2    |
                grep -Fixnf ./list.txt          |
                sed -e's|:*\([0-9]*\).*|:\1|p'  \
                    -e's||\1!{p;n;b\1|p'        \
                    -e's||};n|'                 |
                sed -nf- -e:n -e'p;n;bn' ./data.tmp
    done        2>/dev/null
)|  wc -l

1293+1 records in
7234+0 records out
474087424 bytes (474 MB) copied, 21.8488 s, 21.7 MB/s
462976

プロセス全体に22秒かかり、出力行数が少なくとも正確であることがわかります。 462976は925952の半分で、入力は半分にする必要があります。

この手法は、dd読み書きがバイト単位で計算できるため有効です。実行していることがわかっている場合は、パイプを介して読み書きできます。入力を中断することもできます。行ごとにconv最大行長サイズで安定して計算できる場合、block精度は同じです。(これは512または{_POSIX_LINE_MAX}

想像力豊かな読者なら、あちこちでいくつかの修正だけで同じ技術があらゆるタイプのストリーミング(さらにはライブログタイプにも適用可能)に適用できると正確に推測できます。(つまり、これを安全に実行するには、最初のdd引数bs=到着obs=)。ただし、それぞれの場合、最大入力行サイズに対していくつかの保証が必要であり、行が合法的に<space>文字で終わることができる場合は、プロセスの前に追加のフィルタリングメカニズムを挿入して末尾の<spaces>がdd剥奪されるのを防ぐ必要があります。dd conv=unblock cbs(これは、各サイズconvのバージョンブロックのすべての末尾のスペースを削除し、改行を追加する\n方法で機能します。)tr私は(un|)expandそのようなフィルタの可能な候補を考えました。

これは最速の方法ではありません。これを行うには見つける必要があります-mエルグsort仕事は期待していましたが、非常に高速でデータと連携します。しかし、それはsed -i状況を少し台無しにします。しかし、どちらの方向に行っても、それは本当だと思います。

答え2

いくつかの異なる方法でこの問題を解決できます。まず、sed単一の実行で複数の式がサポートされます。

sed -i -e '/^[^,]*,[^,]*hotmail/Id' -e '/^[^,]*,[^,]*gmail/Id' -e '/^[^,]*,[^,]*yahoo/Id' data.txt

単一の式でこれを行うこともできます。

sed -i -e '/^[^,]*,[^,]*\(hotmail\|gmail\|yahoo\)/Id' data.txt

、、、、(およびすべてエスケープ)する|必要があります。

関連情報