시작 키워드와 끝 키워드 사이에 줄을 복사하여 붙여넣는 방법은 무엇입니까?

시작 키워드와 끝 키워드 사이에 줄을 복사하여 붙여넣는 방법은 무엇입니까?

두 개의 텍스트 파일이 있는데 한 파일에서 다른 파일로 여러 줄을 복사하고 싶습니다. 파일 1에는 패키지 목록이 있으며 이를 목록 2에 복사하고 싶습니다. 이 패키지 목록은 파일 1의 시작 부분에 있지 않지만 목록 시작 부분에 %packages 태그가 있고 끝에 %end 태그가 있습니다. %packages와 %end 사이의 모든 줄을 파일 1에서 파일 2로 복사하는 방법을 알고 싶습니다.

답변1

%packages와 %end 사이의 모든 줄을 file1에서 file2로 복사하려면 다음을 수행하세요.

awk '$1=="%end" {f=0;next} f{print;next} $1=="%packages" {f=1}' file1 >>file2

이 해결 방법은 %packages 및 %end 줄을 제거하는 것입니다. (이 줄도 이동하려면 아래에 더 간단한 해결 방법이 있습니다.)

awk파일의 모든 행에 대해 암시적으로 반복되므로 위 명령이 적용됩니다 . file1이 명령은 호출된 플래그를 사용하여 f의 패키지 섹션 내에 있는지 확인합니다 file1. 패키지 섹션의 각 줄은 stdout으로 인쇄된 다음 file2.

awk다음 명령을 하나씩 살펴 보겠습니다 .

  • $1=="%end" {f=0;next}

    이 명령은 행이 로 시작하는지 확인합니다 %end. 그렇다면 플래그가 0으로 설정되고 해당 행 f으로 점프합니다 .next

  • f{print;next}

    이 명령은 플래그가 f0이 아닌지 확인합니다. 0이 아니면 줄을 인쇄하고 다음 줄로 점프합니다.

  • $1=="%packages" {f=1}

    이 명령은 행이 로 시작하는지 확인합니다 %packages. 그렇다면 플래그를 f1로 설정하여 그 이후의 행을 인쇄합니다.

마커 라인을 포함합니다:

위의 내용에는 %packages 및 %end 표시 줄이 포함되지 않습니다. 이를 포함하려면 다음을 사용하십시오.

awk '/^%packages/,/^%end/ {print}' file1 >>file2

답변2

awk 외에도 고려해야 할 또 다른 솔루션은 sed입니다.

sed -n '/%packages/,/%end/ w file2' file1

출현 순서대로 분류:
sed분명히 그 자체 다음에는 개구부가 있습니다 '. 이는 sed에게 이 시점부터 끝까지 '모든 것이 sed 자체에 대한 인수/명령임을 알려줍니다. 그 이후의 모든 내용은 입력됩니다(또는 리디렉션 > 파일을 사용하는 경우 출력).

-n인쇄를 억제합니다. 이것이 없으면 file1의 전체 내용이 인쇄되고 일치하는 텍스트가 두 번 인쇄됩니다.

/pattern1/,/pattern2/일치시킬 범위의 한계를 정의하십시오.

w file파일에 씁니다. 마지막 매개변수여야 하며 그 뒤에 파일 이름(또는 현재 디렉터리에 없으면 /path/to/file)이 와야 합니다.

마지막으로, 싱글을 닫은 후 '입력 파일을 갖게 됩니다.

두 가지 마지막 메모:

1. 일부 사람들은 입력 파일에 리디렉션을 사용하기를 좋아하므로 최종 명령은 다음과 같습니다.

sed -n '/%packages/,/%end/ w file2' <file1

장점은 더 명확하다는 것입니다. 즉, 입력을 어디서 받는지 분명합니다. 마찬가지로 다음 w file을 사용하는 대신 출력을 >file로 리디렉션할 수 있습니다.

sed -n '/%packages/,/%end/ p' <file1 >file2

이 경우 p인쇄 일치 항목을 추가합니다(선택을 위해 -n 재정의).

그러나 sed는 여러 입력 파일에서 작동할 수 있습니다.

sed -n '/%packages/,/%end/ w file-final' file1 file2 file3

리디렉션을 사용하면 사용자가 이 기능을 무시하는 경우가 많습니다.

2. 위의 일치에는 시작 줄과 끝 줄이 포함됩니다. sed는 단어 수준이 아닌 줄 수준에서 작동하기 때문입니다. 한 가지 해결책은 단순히 더 많은 sed로 파이프하는 것입니다.

sed -n '/%packages/,/%end/ w file2' file1 | sed -e '1d' -e '$d'

다음과 같은 새로운 기능이 도입되었습니다.
-e동일한 입력에서 여러 명령을 실행할 수 있습니다. 일치하는 패턴을 제거하여
1표시 줄 번호 일치가 작동합니다
d. 첫 번째 명령의 줄 번호 1은
$입력 스트림의 끝입니다. sed는 단어 수준이 아닌 줄 수준에서 작동하므로 끝 부분의 전체 줄이 삭제됩니다.

그러나 실제로 그룹화를 위해 중괄호를 사용하여 단일 sed 호출에서 이 작업을 수행할 수 있습니다(명확성을 위해 스크립트에서).

#!/bin/bash
sed -n '
  /%packages/,/%end/ {
    /%packages/n
    /%end/ !{
      w file2
    }
  }
' file1

여기서 (그룹화 외에) 유일한 새로운 점은 !일치 항목을 부정하는 것입니다.
/pattern/n패턴으로 인쇄된 선을 억제합니다( -n처음과 동일). /pattern/ !패턴과 일치하지 않는 모든 항목을 선택합니다(역일치). 그런데 그 이유는 간단합니다. %end 패턴을 억제하기 위해 또 다른 조치를 취하면 /%end/n범위를 제한하기 위해 이를 억제하고 파일은 끝까지 인쇄됩니다.

답변3

가장 이해하기 쉬운:

grep -A 1000 '%packages' xx | grep -B 1000 '%end'

첫 번째 부분은 %packages1000줄(일치하는 줄 포함)을 검색하고 인쇄합니다. 그 후에.

파이프 뒤의 두 번째 부분: %end1000줄(일치하는 줄 포함)을 모두 검색하고 인쇄합니다.두번째 전에.

파일이 1000줄을 초과하는 경우 1000을 더 큰 숫자로 변경하세요.

네가 원한다면오직시작 및 종료 정규 표현식을 포함하여 검색 패턴만 포함하는 행을 일치시킵니다. 이자형.

grep -A 1000 '^%packages$' xx | grep -B 1000 '^%end$'

일치하는 줄을 포함하지 않으려면 다른 파이프를 추가하세요.

grep -A 1000 '^%packages$' xx | grep -B 1000 '^%end$' | grep -v -e '^%packages$' -e '^%end$'

여기서는 -e여러 검색 패턴을 지정하고 -v일치의 의미를 바꾸어 일치하지 않는 행을 선택하는 데 사용할 수 있습니다.

관련 정보