![행에서 숫자를 추출하여 변수에 저장하는 방법은 무엇입니까?](https://linux55.com/image/15265/%ED%96%89%EC%97%90%EC%84%9C%20%EC%88%AB%EC%9E%90%EB%A5%BC%20%EC%B6%94%EC%B6%9C%ED%95%98%EC%97%AC%20%EB%B3%80%EC%88%98%EC%97%90%20%EC%A0%80%EC%9E%A5%ED%95%98%EB%8A%94%20%EB%B0%A9%EB%B2%95%EC%9D%80%20%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C%3F.png)
나는 이것이 매우 간단한 질문이라고 생각하며 Google에서 질문의 일부에 대한 답변을 많이 찾았지만 함께 연결하려고 하면 작동하지 않고 이유를 이해할 수 없습니다.
시나리오는 다음과 같습니다.
- 텍스트가 많은 파일이 있습니다.
- 줄 중 하나가 다음 패턴과 일치합니다.
foo = 1700;
- 추출하고 싶어요
1700
- 나중에 스크립트에서 참조할 수 있도록 bash 스크립트 변수에 저장하고 싶습니다.
3단계를 못 넘어가네요. 내가 시도한 것은 다음과 같습니다.
sed -nE 's/^foo = //p' file | sed -nE 's/;//p'
이것은 다음과 같이 인쇄됩니다:
1700
괜찮습니다. 하지만 공백 등을 다듬어야 한다면 어떻게 해야 할까요? *
/ 를 사용할 수 없으면 +
어떻게 해야 할지 모르겠습니다. 다른 답변을 사용 *
/ +
대체할 수 없다는 점을 이해하므로 이를 수행하는 방법을 모르겠습니다. grep에 대한 매뉴얼 페이지를 살펴보았는데 해당 용어를 검색해도 그룹 옵션이 표시되지 않습니다. 나는 awk에서 이 문제를 해결하는 방법을 알고 있다고 생각하지만 항상 정규식 함수가 약간 투박하고 명령줄 스크립트에 너무 많은 이스케이프가 필요하므로 이상적으로 이것이 이 문제를 해결하는 유일한 방법은 아닙니다. .
답변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 캡처 그룹으로만 바꾸려고 시도하고 성공하면 수정된 줄을 인쇄합니다.
sed
다음으로 출력을 변수에 넣기를 원합니다 . 너는 이걸로 해명령 대체. 예를 들어$ myvar=$(echo 'foo = 1700;' | sed -n -E -e 's/^foo = ([0-9]+).*/\1/p') $ echo $myvar 1700
스크립트에서 사용하려면 파일을 파이프하는 대신 sed에 대한 인수로 사용하세요
echo ...
.myvar=$(sed -n -E -e 's/^foo = ([0-9]+).*/\1/p' file)
공백을 다듬거나
=
선택적 선행 공백이나 주변 선택적 공백 등이 있을 수 있는 줄을 처리합니다.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
다음을 수행할 수 있습니다.-o
perl
-P
grep -Po 'foo\s*=\s*\K\d+'
어디:
\s
공백 문자와 일치*
0개 이상의 선행 원자. 예를 들어\s*
0개 이상의 공백 문자를 일치시킵니다.\d
십진수와 일치합니다(일반적으로 와 동일[0123456789]
하지만[0-9]
일반적으로 더 이상 문자는 사용하지 않음).+
하나 이상의 이전 원자와 일치합니다.\K
일치하는 부분(콘텐츠가 eep로, 또는K
출력의 경우)의 시작을 재설정합니다.grep -o
o
따라서 이것은 주어진 줄에 둘 이상의 숫자가 나타나더라도 하나 이상의 숫자와 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
테스트를 거쳐 잘 작동함