sed/awk를 사용하여 두 패턴 사이의 단어 변경

sed/awk를 사용하여 두 패턴 사이의 단어 변경

일부 텍스트를 처리해야 하는 쉘 스크립트를 작성 중인데 다음과 같은 텍스트가 표시됩니다.

read build { file1 file2 file3 }
check build { file2 file3 file4 }
read build { file4 file5 file6 }

모든 파일 앞에 텍스트를 추가하고 싶습니다. 즉, "읽기 빌드" 줄의 괄호 사이에 포함된 단어를 의미합니다. 이를 달성하는 가장 좋은 아이디어는 무엇이라고 생각하십니까? 결과는 다음과 같아야 합니다.

read build { MY_ADDED_WORDfile1 MY_ADDED_WORDfile2 MY_ADDED_WORDfile3 }
check build { file2 file3 file4 }
read build { MY_ADDED_WORDfile4 MY_ADDED_WORDfile5 MY_ADDED_WORDfile6 }

줄을 잡아서 배열로 구문 분석하고 이 "파일" 문자열을 추가하려는 단어와 연결하려고 합니다. 하지만 이것이 "스마트" 솔루션이라고 생각하지 않습니다. 당신의 도움을 주셔서 감사합니다.

입력 파일은 다음과 같습니다.

set build { file1 file2 file3 file4 }
check $build

read build -new -f $build
read build -new -f { fileA fileB fileC fileD }

set build {file5 file6 file7 }

read build -old -f $build
read build -old -f { fileX fileZ fileD }

check_that_building

출력은 다음과 같아야 합니다.

set build { file1 file2 file3 file4 }
check $build

read build -new -f $build
read build -new -f { MY_ADDED_WORDfileA MY_ADDED_WORDfileB MY_ADDED_WORDfileC MY_ADDED_WORDfileD }

set build {file5 file6 file7 }

read build -old -f $build
read build -old -f { MY_ADDED_WORDfileX MY_ADDED_WORDfileZ MY_ADDED_WORDfileD }

check_that_building

왼쪽 괄호 앞에는 항상 공백이 있지만 오른쪽 괄호 앞에는 공백이 있을 수 있지만 항상 그런 것은 아닙니다. 가능한 상황:

read build -old -f { fileX fileZ fileD }
read build -old -f {fileX fileZ fileD }
read build -old -f { fileX fileZ fileD}
read build -old -f {fileX fileZ fileD}

답변1

sed 입력에 전혀 나타나지 않는 것으로 알려진 문자가 하나 이상 있다고 가정하지 않고는 이 작업을 수행하는 방법을 즉시 알아낼 수 없습니다. 나는 그것이 #입력(또는 당신이 추가한 단어)에 결코 나타나지 않을 것이라고 가정합니다. 이것은 작동하는 것 같습니다:

sed '/read build/ {
        s/{/{ /
        : fruit
        s/\({.*\) \([^}# ][^ ]*\)/\1#MY_WORD\2/
        t fruit
        s/#/ /g
        s/{ /{/
}'

이를 포함하는 줄에서는 read build 그 뒤에 공백이 삽입됩니다 {. 그런 다음 { 단어 뒤와 단어(파일 이름일 수 있음) 바로 앞의 공백을 검색합니다 . 공백을 바꾸고 #단어를 삽입한 다음 다시 돌아가서 더 많은 내용을 찾습니다. ( fruit임의의 루프 레이블입니다.) 모든 문자를 찾으면 #모든 문자를 다시 공백으로 변환하고 삽입한 공백(뒷면 {)을 제거합니다.

#입력에 나타나지 않는 입력에 대한 정보 외에 다음과 같은 정보도 가정됩니다.

  • }각 줄의 공백이 아닌 마지막 문자입니다 read build.
  • 공백은 공백일 뿐입니다. 탭이 없습니다.

존재하다 awk:

awk '/read build/ {
        in_braces=0
        for (i = 1; i <= NF; i++) {
                if ($i == "{") in_braces=1
                else if (substr($i,1,1) == "{") {
                        $i = "{MYWORD" substr($i,2)
                        in_braces=1
                }
                else if ($i == "}") in_braces=0
                else if (in_braces) $i = "MY_WORD" $i
        }
      }
      { print }'

read build행에 대해 해당 행의 모든 ​​단어(필드)를 반복합니다. 상태 변수( )를 사용하여 a와 a 사이에 in_braces있는지 추적합니다 . 그렇다면 추가한 단어로 시작하도록 각 단어를 수정합니다. 이는 약간 다른 두 가지 상황을 처리해야 한다는 점에 유의하세요.{}

  • 만약에 한마디 {, 모든 후속 단어 수정을 시작하도록 플래그를 설정하고
  • 만약에 한마디다음으로 시작됨 {, 실제로는 형식의 복합이므로 수정하세요.{fileX그것{, 추가된 단어와fileX파일 이름. 또한 모든 후속 단어를 수정하기 위한 플래그를 설정합니다.

이는 탭 문자를 단어 구분 기호로 허용하지만 공백을 단일 공백으로 축소하는 단점이 있습니다. 예를 들어 다음을 입력합니다.

read build    {    file1    file2    file3    }

출력을 생성합니다

read build { MY_WORDfile1 MY_WORDfile2 MY_WORDfile3 }

게다가 이는 다음과 같이 가정합니다.

  • the는 {단어의 시작 부분에 있습니다(즉, 앞에 공백이 옵니다).
  • }각 줄의 공백이 아닌 마지막 문자 또는 read build별도의 단어(예: 앞뒤에 공백 포함)

예를 들어, 여러 세트의 중괄호를 허용합니다.

read build { file1 file2 file3 } text to be left alone { file4 file5 file6 }

관련 정보