sed는 하나의 명령으로 여러 항목을 삭제하여 데이터를 삭제합니다.

sed는 하나의 명령으로 여러 항목을 삭제하여 데이터를 삭제합니다.

다음 sed명령을 사용하여 다음이 포함된 이메일을 삭제하고 있습니다 hotmail. 동시에 여러 항목을 확인할 수 있습니까? list.txt(한 줄에 하나의 항목) 에서 로드하는 것이 좋습니다 .

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의 경우 sed두 번째 호출하면 작동합니다...-i '' -esed

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

이렇게 하면...

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

...두 번째 줄에서 GNU는 일치하는 항목을 모두 제거 sed합니다 .dlist.txt대소문자를 구분하지 않지만 대부분의 다른 구문 오류와 동일합니다.

각 행에 대해 실행되는 스크립트의 시작 부분에 있는 두 번째 필드의 첫 번째 필드와 @첫 번째 필드 이전의 모든 항목과 첫 번째 필드를 제거하여 일치 항목을 구체화한 다음 일치 확인을 수행하고 행이 모든 일치 항목을 통과하면 ets는 A를 저장합니다. 이전 공간의 스크립트 상단에 있는 줄의 복사본입니다 g. h이렇게 하면 매 게임마다 이 작업을 수행 sed할 필요가 없습니다 . /^[^,]*,[^,]*.../만약에list.txt시간이 오래 걸리더라도 결코 빠른 과정이 아닐 것입니다. grep -F이 경우 선호되어야합니다(아마도 이 경우).


둘다sedgrep 할 수 있는성능 향상 - 대부분의 경우확실히따라서 - 사용된 문자 세트의 크기가 줄어든 경우. 예를 들어, 현재 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

    • 처음 두 개는 입력 라인을 다음과 같이 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다른 스크립트를 작성합니다 .sed( grep라인 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> 문자로 끝날 수 있는 경우 프로세스 앞에 추가 필터링 메커니즘을 삽입하여 후행 dd<spaces>가 박탈되는 것을 방지해야 합니다.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

, (, ), |및 모두 이스케이프되어야 합니다.

관련 정보