다음 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 '' -e
sed
sed -ne's|[]\*&^.$/[]|\\&|g' \
-e's|..*|/^@&",/d|p' <./list.txt |
sed -ie'h;s/[^,]*[^@]*//' -f- -eg ./data.txt
이렇게 하면...
-e's|..*|/^@&",/Id|p' ...
...두 번째 줄에서 GNU는 일치하는 항목을 모두 제거 sed
합니다 .d
list.txt
대소문자를 구분하지 않지만 대부분의 다른 구문 오류와 동일합니다.
각 행에 대해 실행되는 스크립트의 시작 부분에 있는 두 번째 필드의 첫 번째 필드와 @
첫 번째 필드 이전의 모든 항목과 첫 번째 필드를 제거하여 일치 항목을 구체화한 다음 일치 확인을 수행하고 행이 모든 일치 항목을 통과하면 ets는 A를 저장합니다. 이전 공간의 스크립트 상단에 있는 줄의 복사본입니다 g
. h
이렇게 하면 매 게임마다 이 작업을 수행 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
. 분석 방법은 다음과 같습니다.
cut | cut
- 처음 두 개는 입력 라인을 다음과 같이
cut
줄입니다 ../data.txt
"foxva****omes****","[email protected]","8*** Rd","Ne***ah","Wi***in","54***","*******"
hotmail.com
- 처음 두 개는 입력 라인을 다음과 같이
grep
grep
그런 다음 이 입력을 패턴 파일의 각 라인-f
과 비교할 수 있습니다.list.txt
-i
대소문자를 구분하지 않는-F
고정 문자열을 사용하여 전체 줄을 일치시키고 출력의 각 줄 시작 부분에 줄 번호를-x
보고합니다 .-n
sed -e
sed
출력을 줄 번호로 제거 하고 아래와 같이grep
다른 스크립트를 작성합니다 .sed
(grep
라인 10과 20이 일치한다고 가정):
:10 10!{p;n;b10 };n :20 20!{p;n;b20 };n
sed -inf-
마지막 것은 stdin을 스크립트로
sed
읽고 한 번만 수행합니다 . 일반적으로 스크립트에서 하듯이 각 입력 줄에 대해 스크립트를 역추적하여 실행-
하지 않고 대신 처음이자 유일한 작업 시간에 스크립트를 실행합니다.sed
입력 - 그것만 해당 테스트는 각 입력 라인에 대해 한 번씩 시도되어야 합니다.이전 예에서 1-9행은
sed
다음을 수행합니다.- 현재 행이 번째 행이 아닌 경우
!
현재10
행 을{
인쇄하고 이를 추가 입력 행으로 덮어쓴 다음 이름이 지정된 레이블 로 역추적합니다 .p
n
b
:
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
, (
, )
, |
및 모두 이스케이프되어야 합니다.