awk †는 " "의 n번째 반복을 찾아 {
다음 " " 문자까지 }
모든 것을 반환할 수 있습니까?
[편집: 네...Ed Morton의 솔루션은 맨 아래에 있습니다.]
† 저는 항상 awk가 해당 작업에 적합한 도구라고 생각했습니다. 다른 아이디어도 환영합니다.
수백 개의 파일에서 텍스트 블록을 분리해야 합니다. 일부 파일에는 블록이 하나만 있지만 다른 파일에는 수십 개가 포함되어 있습니다.
견본:
$ cat samp2.txt
//////////////////////////////////
// North Carolina office
// satellite branch
//////////////////////////////////
{
first "John"
last "Doe"
address "163 Main Street"
age "25"
gender "male"
}
>
현재 청크를 임시 파일에 넣어 스크립트가 다음 청크를 처리하기 전에 이를 조작할 수 있도록 하는 것이 좋습니다 . 그럼에도 불구하고 그들은 별도의 파일로 종료됩니다.
나는 n 번째 일치 항목을 찾기 위해 awk에 색인을 제공하는 것이 가능하다고 생각합니다. Bash 스크립트는 루프와 반복을 관리할 수 있습니다.
나는 가깝다
$ awk '/\{/{flag=1;next}/\}/{flag=0}flag' samp2.txt
first "John"
last "Doe"
address "163 Main Street"
age "25"
gender "male"
그러나 위의 작업은 전체 파일에 대해 수행되므로 여러 블록이 포함된 파일(예: 아래와 같은)에서는 작동하지 않습니다. 파일에 블록이 몇 개 있든 관계없이각 블록이 분리되어 있습니다.별도로 처리해야 합니다.
일부 파일에는 주석이 포함되어 있지만 많은 파일에는 주석이 포함되어 있지 않습니다. 표준이 없습니다. 나는 그것들을 폐기했지만 불일치로 인해 해당 댓글을 사용하여 우리 위치를 추적할 수 없었습니다. 주어진 유일한 것은 중괄호(및 줄 구분 기호)입니다.
텍스트는 항상 줄 바꿈으로 구분되지만 블록 사이에 항상 빈 줄이 있는 것은 아닙니다. 데이터 쌍은 다양하므로 이는 간단한 grep 5 lines and proceed
솔루션이 아닙니다.
$ cat samp3.txt
//GROUP1
{
first "John"
address "124 Main Street"
last "Jones"
special "supervisor"
age "35"
gender "male"
}
//The fourth group
{
first "John"
address "125 Main Street"
last "Jacob"
age "30"
gender "male"
}
{
first "John"
address "523 Main Street"
last "Jingle"
age "40"
gender "male"
}
위의 awk 설명은 모든 그룹을 거쳐 하나의 큰 단락으로 병합됩니다.
$ awk '/\{/{flag=1;next}/\}/{flag=0}flag' samp3.txt
first "John"
address "124 Main Street"
last "Jones"
special "supervisor"
age "35"
gender "male"
first "John"
address "125 Main Street"
last "Jacob"
age "30"
gender "male"
first "John"
address "523 Main Street"
last "Jingle"
age "40"
gender "male"
{
다음과 같이 awk에게 n번째 " "를 찾은 다음 }
n번째 " "를 개별적으로 덤프하라고 지시해야 합니다 .
first "John"
address "124 Main Street"
last "Jones"
special "supervisor"
age "35"
gender "male"
(awk exits, bash script does its thing)
first "John"
address "125 Main Street"
last "Jacob"
age "30"
gender "male"
(awk exits, bash script does its thing)
first "John"
address "523 Main Street"
last "Jingle"
age "40"
gender "male"
(awk exits, bash script does its thing)
[etc]
의도는 { .+ }
탐욕스럽지 않은 n번째 " " 정규식 일치와 유사합니다.
이것으로 더 똑똑한 Perl 솔루션이 있을까요?
티아.
이 코드는 내가 필요한 것을 얻습니다. Ed Morton의 답변을 바탕으로 수정되었습니다.
awk -v n=$LoopVariable -v RS='}' 'NR==n{gsub(/.*\{\r?\n|\n$/,""); print}' $SourceFile
편집: 입력 내용은 제가 필요한 질문과 질문을 분리하는 데 정말 도움이 되었습니다. 감사합니다.
찾았어요 일부 SE 문제저것매우 비슷해 보인다, 그러나 여기에 내 솔루션이 포함되어 있으면 연결을 볼 만큼 awk에 대해 충분히 알지 못합니다.
답변1
귀하의 질문에서 예상되는 출력을 보지 못했기 때문에 확실하지 않지만 Can awk † find the nth iteration of a "{" and return everything up to the next "}" character?
이것이 당신이 원하는 것이라고 말씀하셨습니다(awk를 사용하고 입력의 다른 곳에는 나타날 수 없다고 가정하십시오) }
.{
$ awk -v n=2 -v RS='}' 'NR==n{gsub(/.*\{\n|\n$/,""); print}' samp3.txt
first "John"
address "125 Main Street"
last "Jacob"
age "30"
gender "male"
쉘 루프에서 호출하려면 다음을 수행하십시오.
$ for i in {1..3}; do
awk -v n="$i" -v RS='}' 'NR==n{gsub(/.*\{\n|\n$/,""); print}' samp3.txt
echo "-----"
done
first "John"
address "124 Main Street"
last "Jones"
special "supervisor"
age "35"
gender "male"
-----
first "John"
address "125 Main Street"
last "Jacob"
age "30"
gender "male"
-----
first "John"
address "523 Main Street"
last "Jingle"
age "40"
gender "male"
-----
그러나 루프에서 awk를 여러 번 호출하는 것보다 원하는 것을 달성하는 더 나은 방법이 거의 확실합니다. 예를 들어 awk를 한 번 호출하여 종결자가 있는 각 청크를 인쇄한 }
다음 추가 처리를 위해 이를 쉘 배열로 읽습니다.
$ readarray -d '}' -t arr < <(awk 'BEGIN{RS=ORS="}"} {gsub(/.*\{\n|\n$/,"")} $0~/[^[:space:]]/' samp3.txt)
$ for i in "${arr[@]}"; do printf '%s\n' "$i"; echo "-----"; done
first "John"
address "124 Main Street"
last "Jones"
special "supervisor"
age "35"
gender "male"
-----
first "John"
address "125 Main Street"
last "Jacob"
age "30"
gender "male"
-----
first "John"
address "523 Main Street"
last "Jingle"
age "40"
gender "male"
-----
그러나 실제로 쉘 루프에서 수행하는 모든 작업은 awk에 대한 단일 호출로 수행되어야 합니다.
답변2
내 코드의 가정은 정확하지 않을 수 있으며, 이는 많은 경우 실패할 수 있음을 의미합니다. 더 효율적인 솔루션이 있을 수 있습니다.
가설 1각 GROUP
블록은 개행 문자로 구분됩니다.
가설 2각 블록에서 작업을 수행하고 싶습니다.
가설 3각 GROUP
블록이 증가합니다(그렇지 않으면 빈 파일이 많아질 수 있습니다).
for i in {1..5}; do
awk -F"\n" -v RS="" -v inc="GROUP$i" '$0~inc{printf( "%s\n", $0); next}' $inputfile | sed '/\/\|{\|}/d' > output$i.txt ;
done
귀하의 예에는 GROUP1&4
하나를 추가 GROUP5
하고 for
1-5 범위에서 증가하는 루프를 작성했습니다. 이 범위는 블록을 통과할 때 키로 사용됩니다 GROUP
. 그룹이 더 많은 경우 그에 따라 범위를 늘릴 수 있습니다.
awk
청크를 추출하기 위해 루프에서 사용됩니다. sed
정리한 다음( awk
한 번에 모두 수행할 수 있지만 아직 배우는 중) 각 청크를 GROUP
청크 수와 일치하는 자체 출력 파일에 씁니다.
입력 파일
//GROUP1
{
first "John"
address "124 Main Street"
last "Jones"
special "supervisor"
age "35"
gender "male"
}
//GROUP4
{
first "John"
address "125 Main Street"
last "Jacob"
age "30"
gender "male"
}
{
first "John"
address "523 Main Street"
last "Jingle"
age "40"
gender "male"
}
//GROUP5
{
first "Maria"
address "188 John Street"
last "Phones"
special "Supervisors supervisor"
age "35"
gender "Female"
}
산출
cat output1.txt
first "John"
address "124 Main Street"
last "Jones"
special "supervisor"
age "35"
gender "male"
cat output4.txt
first "John"
address "125 Main Street"
last "Jacob"
age "30"
gender "male"
first "John"
address "523 Main Street"
last "Jingle"
age "40"
gender "male"
cat output5.txt
first "Maria"
address "188 John Street"
last "Phones"
special "Supervisors supervisor"
age "35"
gender "Female"
답변3
거의 다 왔어요... 코드를 약간 조정하면 별도의 청크가 생성됩니다.
awk -v n="$loopVar" '/\{/{f=1;++i;next} /\}/{f=0} i==n&&f' file
지침:-
/\{/
어디에서나 여는 중괄호와 일치합니다.- 약간 더 나은 점은 다음과 같습니다.
NF==1&&$1=="{"
- 닫는 중괄호도 마찬가지입니다.
- awk 전에 유틸리티를 통해 입력 파일을 실행하여
dos2unix
캐리지 리턴을 지웁니다.\r