동일한 디렉토리에 여러 개의 파일(예: file1
, ...etc.)이 있고 각 파일에는 여러 줄의 일치 항목이 포함될 수 있습니다. 각 행에서 번째 행을 제거하고 싶습니다(예: match = 및 content).file2
PATTERN
N
PATTERN
N
3
file1
1 no match
2 PATTERN
3 same PATTERN
4 no match here
5 no match here either
6 another PATTERN
7 again, no match
8 no
9 last line
예상 출력은 다음과 같습니다.
1 no match
2 PATTERN
3 same PATTERN
4 no match here
7 again, no match
8 no
파일을 제자리에서 편집하는 것은 필수 사항이 아니라 보너스입니다(비록 gnu
모든 파일을 한 번에 편집할 수 있는 도구를 하나 이상 알고 있지만...).
비슷한 질문을 하신 분이 계시네요여기그러나 이것은 특별한 경우입니다. 각 파일의 한 줄만 패턴과 일치하며, 거기의 솔루션은 적어도 다음과 같이 표현되는 경우 패턴과 일치하는 여러 줄에 대해서만 작동합니다.질소일치하지 않는 행의 경우 +1).
답변1
나는 당신 awk
이 다음과 같이 사용할 수 있다고 믿습니다 :
awk -vN=3 '/PATTERN/ {skips[FNR+N]=1;} {if(!(FNR in skips)) print;}' <file>
따라서 클릭할 때마다 PATTERN
여기에서 줄을 기록하고 N
건너뛴 것으로 표시하지 않은 줄만 인쇄합니다.
-i inplace
gawk를 사용하면 내부에서 수행 할 수도 있습니다 .
지적했듯이 이것은 여러 파일을 처리하지 않습니다. 물론 for
루프를 사용하여 모든 파일을 반복할 수 있지만 파일이 충분하지 않아 명령줄을 너무 길게 만들 수도 있습니다.
awk -vN=3 '{if(FNR==1) split("", skips, ":");} /PATTERN/ {skips[FNR+N]=1;} {if(!(FNR in skips)) print;}' *
skips
1에 도달할 때마다 FNR
각 파일의 시작 부분인 빈 배열로 재설정됩니다. 다음과 같이 작성할 수 있습니다
.gnu awk
gawk -i inplace 'FNR==1{delete nr};/PATTERN/{nr[FNR+3]++};!(FNR in nr)' file*
답변2
저는 2패스 메커니즘을 좋아하므로 다음을 사용할 수 있습니다 sed -i
.
for file in file1 ...
do sed -i "$file" -e "$(awk <"$file" -v N=3 '/PATTERN/{ print (NR+N) "d" }')"
done
답변3
for f in file1 file2 file...; do
sed -i -f <(grep -n PATTERN "$f" | while IFS=: read line rest; do printf "%dd; " $((line+3)); done) "$f"
done
분리하세요:
file1 file2 파일을 반복합니다...
프로세스 대체에서 sed 표현식을 빌드하고 최종적으로 파일에 대해 실행합니다.
grep
파일의 PATTERN과 일치하는 라인 번호(및 실제 일치하는 라인)를 출력합니다.
예제 출력:
2:2 PATTERN
3:3 same PATTERN
6:6 another PATTERN
while 루프는 줄 번호를 제거하고, 일치하는 줄을 버리고, 3씩 증가시켜 printf로 보냅니다.
printf는 대상 행 번호를 인쇄한 다음 sed
d
delete 명령과 구분 세미콜론을 인쇄합니다.
출력 예(입력으로 sed
):
5d; 6d; 9d;
이 방법을 사용하면 printf 매개변수 N=3
로 설정하고 사용할 수 있어 많은 유연성을 얻을 수 있습니다 .$((line+N))
내부 편집을 설명하기 위해 sed가 -i
"내부" 편집을 지원한다고 가정하겠습니다.
답변4
이 사용 사례는 단지빌다사용하기위한 ex
.
불행히도 세 번째 줄을 제거한 이후뒤쪽에주어진 라인은 PATTERN을 포함하는 라인을 삭제할 수 있으며, 이로 인해 해당 라인과 관련된 삭제가 건너뛰게 됩니다(더 나쁘게는 잘못된 라인이 삭제되는 경우). tac
먼저 예를 들어 파일을 되돌려야 합니다. 그런 다음 세 번째 줄을 삭제하십시오.앞으로PATTERN의 각 인스턴스를 삭제하고 파일을 다시 되돌립니다.
for f in *.txt; do printf %s\\n '%!tac' 'g/PATTERN/-3d' '%!tac' x | ex "$f"; done
사용 가능한 것이 있다면 tac
이것이 가장 깨끗한 솔루션이라고 생각합니다.
POSIX와 완전히 호환되는 솔루션, 내 답변을 사용하여:
다음을 수행할 수 있습니다.
for f in *.txt; do printf %s\\n '%!sed -n '\''1h;1\!{x;H;};${g;p;}'\' 'g/PATTERN/-3d' '%!sed -n '\''1h;1\!{x;H;};${g;p;}'\' x | ex "$f"; done
읽기 쉽지는 않지만 유용합니다.