행에서 숫자를 추출하여 변수에 저장하는 방법은 무엇입니까?

행에서 숫자를 추출하여 변수에 저장하는 방법은 무엇입니까?

나는 이것이 매우 간단한 질문이라고 생각하며 Google에서 질문의 일부에 대한 답변을 많이 찾았지만 함께 연결하려고 하면 작동하지 않고 이유를 이해할 수 없습니다.

시나리오는 다음과 같습니다.

  1. 텍스트가 많은 파일이 있습니다.
  2. 줄 중 하나가 다음 패턴과 일치합니다.foo = 1700;
  3. 추출하고 싶어요1700
  4. 나중에 스크립트에서 참조할 수 있도록 bash 스크립트 변수에 저장하고 싶습니다.

3단계를 못 넘어가네요. 내가 시도한 것은 다음과 같습니다.

sed -nE 's/^foo = //p' file | sed -nE 's/;//p'

이것은 다음과 같이 인쇄됩니다:

1700

괜찮습니다. 하지만 공백 등을 다듬어야 한다면 어떻게 해야 할까요? */ 를 사용할 수 없으면 +어떻게 해야 할지 모르겠습니다. 다른 답변을 사용 */ +대체할 수 없다는 점을 이해하므로 이를 수행하는 방법을 모르겠습니다. grep에 대한 매뉴얼 페이지를 살펴보았는데 해당 용어를 검색해도 그룹 옵션이 표시되지 않습니다. 나는 awk에서 이 문제를 해결하는 방법을 알고 있다고 생각하지만 항상 정규식 함수가 약간 투박하고 명령줄 스크립트에 너무 많은 이스케이프가 필요하므로 이상적으로 이것이 이 문제를 해결하는 유일한 방법은 아닙니다. .

답변1

  1. 먼저 숫자 값을 캡처하는 방법을 소개하겠습니다.

    $ echo 'foo = 1700;' | sed -n -e 's/^foo = \([0-9]\+\).*/\1/p'
    1700
    

    이는 sed기본 BRE(Basic Regular Expressions)를 사용합니다. sed -E옵션 과 함께 확장 정규식(ERE)을 사용할 수도 있습니다 .

    echo 'foo = 1700;' | sed -n -E -e 's/^foo = ([0-9]+).*/\1/p'
    1700
    

    [0-9]+괄호 안의 하위 표현식은 (... )하나 이상의 숫자를 캡처합니다. 이를 "캡처 그룹"이라고 하며 다음으로 대체하는 데 사용됩니다 \1.첫 번째캡처 그룹 - 캡처 그룹이 여러 개인 경우 \1, \2, \3 등으로 사용할 수 있습니다.

    이 경우 sed 스크립트는 전체 줄을 \1 캡처 그룹으로만 바꾸려고 시도하고 성공하면 수정된 줄을 인쇄합니다.

  2. sed다음으로 출력을 변수에 넣기를 원합니다 . 너는 이걸로 해명령 대체. 예를 들어

    $ myvar=$(echo 'foo = 1700;' | sed -n -E -e 's/^foo = ([0-9]+).*/\1/p')
    $ echo $myvar
    1700
    
  3. 스크립트에서 사용하려면 파일을 파이프하는 대신 sed에 대한 인수로 사용하세요 echo ....

    myvar=$(sed -n -E -e 's/^foo = ([0-9]+).*/\1/p' file)
    
  4. 공백을 다듬거나 =선택적 선행 공백이나 주변 선택적 공백 등이 있을 수 있는 줄을 처리합니다.

    myvar=$(sed -n -E -e 's/^[[:space:]]*foo[[:space:]]*=[[:space:]]*([0-9]+).*/\1/p' file)
    

    sed의 일부 버전(적어도 GNU sed, 어쩌면 다른 버전)은 이것을 이해 perl's \s하므로 다음과 같이 단축할 수 있습니다.

     myvar=$(sed -n -E -e 's/^\s*foo\s*=\s*([0-9]+).*/\1/p' file)
    

답변2

완전성을 위해 및 를 지원하는 정규식 구현을 사용하여 grep다음을 수행할 수 있습니다.-operl-P

grep -Po 'foo\s*=\s*\K\d+'

어디:

  • \s공백 문자와 일치
  • *0개 이상의 선행 원자. 예를 들어 \s*0개 이상의 공백 문자를 일치시킵니다.
  • \d십진수와 일치합니다(일반적으로 와 동일 [0123456789]하지만 [0-9]일반적으로 더 이상 문자는 사용하지 않음).
  • +하나 이상의 이전 원자와 일치합니다.
  • \K일치하는 부분(콘텐츠가 eep로, 또는 K출력의 경우)의 시작을 재설정합니다.grep -oo

따라서 이것은 주어진 줄에 둘 이상의 숫자가 나타나더라도 하나 이상의 숫자와 foo=양쪽에 허용되는 공백 수 의 모든 시퀀스를 인쇄합니다.=

를 사용하면 일치하는 전체 부분이 아닌 주어진 캡처 그룹이 일치하는 항목을 인쇄하기 위해 pcregrep그 뒤에 숫자를 지정할 수도 있습니다 .-o

pcregrep -o1 'foo\s*=\s*(\d+)'

이식 가능하면 실제로 실제를 사용할 수 있습니다 perl. ::

perl -lne 'print $1 for m{foo\s*=\s*(\d+)}g'

답변3

숫자 값 을 선택한다고 가정해 보겠습니다 foo.

echo 'foo = 1700;' | awk '$1=="foo" {print $NF+0}'
1700

기본적으로 awk공백(단지 단일 공백이 아님)으로 분할됩니다. NF는 필드 수입니다. 이 경우 3은 $NF세 번째 공백 필드의 문자열 값입니다. +0이 문자열을 1700;숫자 값으로 변환합니다 1700.

와 같은 라인에서는 작동 foo = 1700;하지만 와 같은 라인에서는 작동하지 않습니다 foo=1700;. 귀하의 질문에 따르면 여분의 공백을 제거하는 데 관심이 있는지, 아니면 데이터에 공백이 없고 및 유일한 경계 지점이 =있을 수 있는지 잘 모르겠습니다 . ;존재 여부에 관계없이 공백을 무시하려면 다음을 사용하는 것이 좋습니다 sed.

echo 'foo=1700;' | sed -n 's/^foo *= *//p' | sed -e 's/;$//' -e 's/ *$//'
1700

답변4

awk '{for(i=1;i<=NF;i++){if($i ~ /foo/ && $0 ~ /foo.*=.*[0-9]*/){gsub(";","",$(i+2));print $(i+2)}}}' filename

테스트를 거쳐 잘 작동함

관련 정보