같은 패턴이 나타날 때까지 교차하는 선을 연결하는 방법

같은 패턴이 나타날 때까지 교차하는 선을 연결하는 방법

파일이 있습니다:

 "p1"data
 "p2"data
 "p3"data
 "p1"data
 "p2"data
 "p3"data
 "p2"data
 "p3"data
 "p1"data
 

다음 "p1"이 나타날 때까지 모든 행을 "p1"로 연결하고 싶습니다.

 "p1"data"p2"data"p3"data
 "p1"data"p2"data"p3"data"p2"data"p3"data
 "p1"data
 

인용문은 문자 그대로의 인용문입니다. 수천 줄의 "p2" 및 "p3" 입력 파일 세트가 1~10개 있을 수 있습니다. 출력 파일의 길이는 약 600줄이어야 합니다.

사용해 보았 sed -e'/^"p1/N;s/\n//'으나 여러 번 실행해야 했고 결국 "p1"을 다른 "p1"과 연결하게 되었습니다.

어떤 도움이라도 대단히 감사하겠습니다. 참고로 이 파일은 XML 파일에서 가져온 것입니다. XML 도구가 있다는 것을 알고 있지만 sed.

답변1

기반으로이것, GNU 사용( sed환경에서 사용할 수 있는 것이 없다고 가정):$POSIXLY_CORRECT

sed ':a;N;/\n"p1"/!s/\n//;ta;P;D' file

표준 sed구문에서는 분기 레이블 뒤에는 주석을 달 수 없으며 N마지막 줄에서 실행하면 패턴 공간이 삭제되므로 다음과 같아야 합니다.

sed -e :a -e '$!N;/\n"p1"/!s/\n//;ta' -e 'P;D' file

추가 댓글:

sed '
  # Label to jump to:
  :a
  # Append next line to pattern space unless we are
  # on the last line:
  $!N
  # If the newline is NOT followed by "p1", append
  # the line by replacing the newline with a space:
  /\n"p1"/!s/\n//
  # If we changed something, jump to label:
  ta
  # Print part until newline
  P
  # Delete part until newline
  D' file

답변2

sed는 좋은 선택이 아닙니다. 모든 Unix 시스템의 모든 쉘에서 awk를 사용하십시오.

$ awk -v ORS= 'NR>1 && /^"p1"/{print RS} {print} END{print RS}' file
"p1"data"p2"data"p3"data
"p1"data"p2"data"p3"data"p2"data"p3"data
"p1"data

답변3

저는 sed가 아닌 Perl을 사용하겠습니다. 왜냐하면 Perl은 여러 줄 문자열을 지원하므로 이를 쉽게 수행할 수 있기 때문입니다.

$ perl -0777 -n -e 's/\n//g; s/"p1"/\n$&/g; s/^\n//; print "$_\n"' input.txt 
"p1"data"p2"data"p3"data
"p1"data"p2"data"p3"data"p2"data"p3"data
"p1"data
  • -0777은 Perl에게 전체 파일을 즉시 메모리로 읽도록 지시합니다(즉, 변수로 "삼키기" $_).
  • -n은 Perl을 다음과 같이 실행합니다 sed -n(즉, 아무것도 자동으로 인쇄하지 않고 입력을 읽습니다).

스크립트는 먼저 모든 줄 바꿈을 제거한 다음 각 줄 앞에 새 줄을 추가한 "p1"다음 문자열 시작 부분에 추가되었을 수 있는 줄 바꿈을 제거합니다(첫 번째 줄이 로 시작한다고 가정 "p1").

마지막으로, 수정된 입력은 후행 개행 문자로 인쇄됩니다(출력이 텍스트 파일에 대해 유효하려면 - Unix 텍스트 파일은 개행 문자로 끝나야 합니다. 많은 도구는 개행 문자로 끝나지 않는 대부분의 텍스트 파일을 잘 처리할 수 있습니다) , 그러나 a) 일부는 그렇지 않습니다. POSIX에 따라 줄 바꿈으로 끝나지 않기 때문에 마지막 "줄"을 처리할 수 없습니다.기술적으로는 "라인"이 아닙니다., b) 입력을 유연하게 받아들이는 것은 좋지만 올바른 출력을 생성하는 것은 훨씬 더 좋습니다. c) 최종 줄 바꿈을 인쇄하지 않으면 보기 흉해 보이고 다음 쉘 프롬프트가 출력과 같은 줄에 나타나게 됩니다. d) 마찬가지로 cat, 여러 파일을 -ing하거나 파일에 텍스트를 추가할 때도 문제가 발생할 수 있습니다. 바라보다파일 끝에 새 줄을 추가하는 이유는 무엇입니까?)

또는:

$ perl -0777 -n -e 's/\n//g; s/(.)("p1")/$1\n$2/g; print "$_\n"' input.txt 
"p1"data"p2"data"p3"data
"p1"data"p2"data"p3"data"p2"data"p3"data
"p1"data

첫 번째 버전과 마찬가지로 이것은 모든 개행 문자를 제거하지만 "p1"다른 문자( .) 뒤의 모든 인스턴스 앞에 개행 문자를 추가합니다. 즉, 첫 번째 줄이 아닙니다. 그런 다음 후행 개행 문자로 수정된 입력을 인쇄합니다.

또 다른 변형이 있습니다:

$ perl -0777 -p -e 's/\n//g; s/(.)("p1")/$1\n$2/g; s/$/\n/' input.txt 
"p1"data"p2"data"p3"data
"p1"data"p2"data"p3"data"p2"data"p3"data
"p1"data

-p대신 Perl의 옵션을 사용합니다 -n. -pPerl이 sed처럼 작동하도록 만듭니다(즉, 입력을 읽고 수정 후 자동으로 인쇄합니다). 그렇지 않으면 위의 두 번째 버전과 매우 유사하지만 s/$/\n/ 자동으로 인쇄하기 전에 입력 끝에 개행 문자를 추가하는 데 사용됩니다.

답변4

ed편집기를 사용하십시오 :

v/^"p1"/ -,. j

이는 부분 문자열로 시작하지 않는 각 줄을 이전 줄과 "p1"연결합니다 .

이는 첫 번째 줄이 "p1"하위 문자열로 시작한다고 가정합니다. 이것이 사실이라는 보장이 없으면 v첫 번째 줄에서 명령을 실행하지 마십시오.

2,$ v/^"p1"/ -,. j

질문에 제공된 데이터에 대해 이를 테스트합니다.

$ printf '%s\n' 'v/^"p1"/ -,. j' ,p Q | ed -s file
"p1"data"p2"data"p3"data
"p1"data"p2"data"p3"data"p2"data"p3"data
"p1"data

관련 정보