awk의 패턴 내에서 쉘 변수 사용

awk의 패턴 내에서 쉘 변수 사용

탭으로 구분된 열이 있는 텍스트 파일이 있는데 awk를 사용하여 처리하고 싶습니다.

다음은 그러한 파일의 예입니다.

size=1\tname=foo\tweight=1.2
weight=2.5\tname=bar\tsize=2

내가 달성하고 싶은 것은 소수점 네 자리와 유사한 내용을 가진 열의 숫자 값을 정규화 $field_name=<number>하고 나머지는 변경하지 않고 유지하는 것입니다. 여기에는 $field_nameawk에 전달된 쉘 변수가 있으며 그 값을 정규 표현식에 사용하고 싶습니다.

다음은 스니펫입니다(물론 작동하지 않습니다). 나는 특히 다른 도구(sed, Perl, Python 등)를 사용하는 솔루션보다는 다음 awk 스크립트의 5행을 수정하는 데 관심이 있습니다.

$ cat "${file}" \                                       # 1
    | awk -F "\t" -v field_name="${external_var}" '     # 2
      {                                                 # 3
        for (i = 1; i <= NF; i++) {                     # 4
          if ($i ~ /$field_name=[0-9]*.?[0-9]+/) {      # 5
            split($i, kv, "=")                          # 6
            $i = sprintf("%s=%.4f", kv[1], kv[2])       # 7
          }                                             # 8
        }                                               # 9
        print $0                                        # 10
      }'

답변1

이는 다음과 같아야 합니다:

if ($i ~ field_name "=[0-9]*.?[0-9]+") ...

또는:

 regexp = field_name "=[0-9]*.?[0-9]+"
 if ($i ~ regexp) ...

.단일 문자는 모두 일치됩니다 . 리터럴을 일치시키려면 (큰따옴표 안에 작성해야 함 ) 또는 를 포함 .해야 합니다 .regexp\.\\.[.]

 regexp = field_name "=[0-9]*\\.?[0-9]+"

또한 정규식을 고정하고 싶기를 바랍니다.

 regexp = "^" field_name "=[0-9]*\\.?[0-9]+$"

기타 참고사항:

  • cat "${file}"$fileUUOC이기 때문에 시작 시 작동하지 않고 -파일을 열 수 없는 경우 계속 실행된다는 단점(리디렉션을 통해)도 있습니다.awk
  • -v field_name="$external_data"백슬래시를 끊습니다. 문제 없는 또 다른 방법은 환경 변수를 사용하고 FIELD="$external_data" awk ...이를 as에서 참조하는 것입니다.awkENVIRON["FIELD"]
  • 의 내용이 field_name그대로 에 복사되므로 regexp정규식으로 처리되므로 $external_data정규식 연산자( ... )를 포함 하면 .+*?{}()[]\^%제대로 작동하지 않을 수 있습니다 .
  • 일부 로케일 및 awk구현 에서는 [0-9]단순한 것보다 더 많은 문자가 일치합니다 0123456789(입력에 나타날 가능성이 없는 (ASCII가 아닌) 문자인 것으로 의심되지만).

그리고 perl:

FIELD=size <"$file" perl -lpe '
  s{
    (?<![^\t])       # not-preceded by a non-TAB
    \Q$ENV{FIELD}=\E # contents of $FIELD taken literally
    \K               # matched portion starts here
    \d*\.?\d+
    (?![^\t])        # not followed by a non-TAB
  }{
    sprintf "%.4f", $&
  }gxe'

awk이는 위에서 설명한 문제를 전혀 나타내지 않습니다(또한 텍스트와 바이너리 데이터의 혼합 또는 사용자의 로케일과 다른 문자 집합으로 인코딩된 텍스트 등 잘못된 텍스트를 포함하는 입력보다 낫습니다 ).

관련 정보