쉘 스크립트에서 하위 문자열 "mode:" 뒤에 숫자 값을 추출하는 간결하지만 읽기 쉬운 방법입니다.

쉘 스크립트에서 하위 문자열 "mode:" 뒤에 숫자 값을 추출하는 간결하지만 읽기 쉬운 방법입니다.

나는 이 문자열을 가지고 있습니다 :

DMT           mode 4: 640x480 @ 60Hz 4:3, clock:25MHz progressive

패턴 번호(첫 번째 :) 앞의 부분을 추출하고 싶습니다. 이 경우 4입니다. 예상한 대로 패턴 번호의 길이는 1자리 또는 2자리일 수 있으며 그 앞의 텍스트 문자 길이가 정확히 동일하다고 믿을 수는 없습니다.

작동하는 솔루션이 있습니다.

$picked = "DMT           mode 4: 640x480 @ 60Hz 4:3, clock:25MHz progressive"
echo $picked | awk -F"mode " '{print $2}' | tr : '\n' | head -n1

그러나 나는 이것을 수행하는 더 우아한 방법이 있어야 한다고 생각합니다. 우아하고 배우기 쉬우며 나중에 읽으십시오(따라서 아마도 정규 표현식이 포함되지 않을 것입니다). 내 꿈의 명령은 다음과 같습니다.echo $picked | "패턴" ":" 사이

다음은 구문 분석 가능한 입력 범위의 필요성을 보여주는 몇 가지 추가 예입니다.

CEA           mode 7: 720x480 @ 60Hz 16:9, clock:27MHz x2 interlaced
CEA  (native)  mode 16: 1920x1080 @ 60Hz 16:9, clock:148MHz progressive
DMT           mode 58: 1680x1050 @ 60Hz 16:10, clock:146MHz progressive

답변1

정규 표현식은 보다 간단한 솔루션입니다. 몇 가지 옵션은 다음과 같습니다.

echo "$picked" | grep -oP '(?<=mode )\d+'
echo "$picked" | grep -oP '(?<=mode )[[:digit:]]+'

PCRE 기능이 마음에 들지 않는 경우:

echo "$picked" | grep -oE 'mode [[:digit:]]+' | tr -d 'mode '

tr명령은 삭제되지 않습니다.단어모든 것을 제거하는 "모드"수치"모델", " ".


당신이 정말 좋아한다면, "패턴"을 클릭할 때까지 단어를 반복합니다.

echo "$picked" | awk '{for (i=1; i<NF; i++) if ($i == "mode") {print $(i+1); exit}}' | tr -d :

문자열이 이미 쉘 변수에 포함되어 있으므로 bash 매개변수 대체는 어떻습니까?

tmp=${picked#*mode }    # remove up to "mode "
value=${tmp%%:*}        # remove the colon and everything after

그 다음에

$ declare -p picked tmp value
declare -- picked="DMT           mode 4: 640x480 @ 60Hz 4:3, clock:25MHz progressive"
declare -- tmp="4: 640x480 @ 60Hz 4:3, clock:25MHz progressive"
declare -- value="4"

인용하다3.5.3 쉘 매개변수 확장설명서에서(그리고 일부 세부 사항을 간략히 설명):

  • ${var#pattern}제거하다가장 짧은 접두사패턴 일치
  • ${var##pattern}제거하다가장 긴 접두사패턴 일치
  • ${var%pattern}제거하다가장 짧은 접미사패턴 일치
  • ${var%%pattern}제거하다가장 긴 접미사패턴 일치

"가장 짧은 것"과 "가장 긴 것"의 차이가 중요합니다. 주어진 문자열 접미사에는 여러 개의 콜론이 포함되어 있습니다. ${tmp%:*}제거할 때만 사용하십시오.마지막콜론과 그 뒤의 문자입니다.

답변2

perlPCRE 스타일 정규식 또는 그 변형을 지원하는 경우 grep직접 일치와 하나 이상의 숫자를 사용하여 값을 선택할 수 있습니다.mode

grep -oP 'mode\s+\K\d+'

나는 당신이 RE를 좋아하지 않는다는 것을 읽었지만 그것은 매우 간단한 패턴이므로 여기서 설명하겠습니다.

  • 지금까지의 모든 내용 \K은 일치해야 하는 역방향 패턴이지만 결과에는 포함되지 않습니다.
  • \s공백과 일치합니다(보통공간또는상표) 접미사에는 +다음 중 하나 이상이 필요합니다.
  • \d숫자 접미사( 0.. 9)와 일치하려면 +다음 중 하나 이상이 필요합니다.

원하는 값에 숫자가 아닌 텍스트가 포함될 수 있다는 것을 알고 있는 경우 \d+로 바꿀 수 있습니다. [^:]+여기서는 [^:]콜론( )을 :제외한 모든 항목이 일치됩니다.

인용하다

답변3

간단하고 직접적인 sed해결책은

sed -n 's/.*mode \([0-9]*\):.*/\1/p'

세 개( ) 대신 단일 명령을 사용하세요 awk | tr | head. 솔루션이 읽기 쉽다고 생각하시면 도와드릴 수 없습니다.

답변4

나는 이미 제공된 Shell 매개변수 확장 솔루션을 좋아하지만 bash를 사용할 수 없는 경우 다음 AWK 체인이 동일한 방식으로 작동합니다.

... |awk -F"mode " '{print$2}' | awk -F: '{print $1}'

첫 번째 awk 호출은 "mode"에서 문자열을 분할하고 그 뒤에 오는 내용을 반환합니다.

두 번째 호출은 이를 :로 분할하고 이전 내용을 반환합니다.

나에게는 이것이 Bash 매개변수 확장보다 더 읽기 쉽습니다. 그러나 더 장황하고 속도도 느릴 수 있습니다(AWK가 상당히 빠른 것으로 알려져 있지만 두 번 시작하는 오버헤드가 이에 반대됩니다).

관련 정보