두 개의 텍스트 파일이 있는데 한 파일에서 다른 파일로 여러 줄을 복사하고 싶습니다. 파일 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}
이 명령은 플래그가
f
0이 아닌지 확인합니다. 0이 아니면 줄을 인쇄하고 다음 줄로 점프합니다.$1=="%packages" {f=1}
이 명령은 행이 로 시작하는지 확인합니다
%packages
. 그렇다면 플래그를f
1로 설정하여 그 이후의 행을 인쇄합니다.
마커 라인을 포함합니다:
위의 내용에는 %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'
첫 번째 부분은 %packages
1000줄(일치하는 줄 포함)을 검색하고 인쇄합니다.ㅏ 그 후에.
파이프 뒤의 두 번째 부분: %end
1000줄(일치하는 줄 포함)을 모두 검색하고 인쇄합니다.두번째 전에.
파일이 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
일치의 의미를 바꾸어 일치하지 않는 행을 선택하는 데 사용할 수 있습니다.