다음 행의 검색 열 인덱스에서 문자열을 추출하시겠습니까?

다음 행의 검색 열 인덱스에서 문자열을 추출하시겠습니까?

간단한 디스크 사용 셸 스크립트(대시)를 만들려고 하는데 AWK 구문에 익숙하지 않기 때문에 문자열을 구문 분석하는 방법을 잘 모르겠습니다.

저는 다음 명령을 사용합니다. df -P -BG /예를 들어 다음과 같은 출력이 표시됩니다.

Filesystem                  xxxxxxxxxx-blocks  Used Available Capacity Mounted on
/dev/mapper/xxx_crypt                    500G  200G      100G      xx% /

"사용됨"(궁극적으로는 "사용 가능") 아래의 열을 추출하고 싶지만 어떻게 해야 할지 잘 모르겠습니다. AWK에는 다음과 같은 검색 명령이 있다는 것을 알고 있습니다.awk '/Used/ {print}'

하지만 그 아래 행을 얻는 방법을 모르겠습니다. 어떤 팁이 있나요? 예를 들어 df -P -BG / | awk '...'쉘 변수에 저장하기 때문에 한 줄에서 파이프로 작동하는 것이 중요 하지만 여러 줄의 AWK를 사용할 수 있으므로 꼭 필요하다고 생각하지 않습니다.

답변1

구현에서 지원하는 경우 구문 분석 대신 df사용할 수 있습니다 . 내 아치 리눅스 --output에서 :man df

--output[=FIELD_LIST]
  use the output format defined by FIELD_LIST, or print all fields if
  FIELD_LIST is omitted.

[...]

FIELD_LIST is a comma-separated list of columns to be included.  
Valid field names  are:  'source',  'fstype',  'itotal',  'iused',
'iavail',  'ipcent', 'size', 'used', 'avail', 'pcent', 
'file' and 'target' (see info page).

따라서 귀하의 경우에는 다음을 수행하십시오.

$ df  -BG --output="used" /
 Used
  200G

정말로 구문 분석이 필요한 경우 패턴 일치에 전혀 신경 쓰지 않을 것입니다. 입력을 제어하면 변경되지 않으므로 세 번째 필드(내 시스템의 출력)만 인쇄할 수 있습니다.

$ df -P -BG / | awk '{print $3}'
Used
44G

필드 순서가 변경되더라도 작동하도록 해야 하는 경우 문자열이 포함된 필드를 찾아야 하는 경우 Used다음과 같이 복잡한 작업을 수행할 수 있습니다.

$ df -P -BG / | 
   awk '{ if(NR==1){for(i=1; i<=NF; i++){ if($i ~ /Used/){want=i}}} print $want}'
Used
44G

답변2

FPAT, FIELDIDTHS, \s, \S 및 gensub()와 함께 GNU awk를 사용하십시오.

$ cat tst.awk
BEGIN { FPAT="\\S+|\\s+"; OFS="\t" }
NR == 1 {
    sub(/Mounted on/,"Mounted_on")
    for ( i=1; i<=NF; i+=2 ) {
        tags[++numTags] = $i
        wids = wids " " length($i $(i+1))
    }
    FIELDWIDTHS = wids
    $0 = $0
}
{
    for ( i=1; i<=NF; i++ ) {
        f[tags[i]] = gensub(/^\s+|\s+$/,"","g",$i)
    }
    print f["Filesystem"], f["Available"], f["Used"]
}

$ cat file | awk -f tst.awk | column -s $'\t' -t
Filesystem             Available  Used
/dev/mapper/xxx_crypt  100G       200G

나에게 없는 것으로 교체하세요 cat file. 정렬을 위해 열을 df -P -BG /파이프로 연결했는데 column이는 필요하지 않습니다.

이렇게 하면 이름으로 인쇄하고, 비교하고, 재정렬하고, 원하는 열의 값에 대해 산술 연산을 수행하는 등의 작업을 수행할 수 있습니다. 코드에서 수정해야 했던 유일한 것은 공백을 밑줄로 변경하여 "설치"하는 것이었습니다.

다음은 모든 awk에서 작동하는 버전입니다.

$ cat tst.awk
BEGIN { OFS="\t" }
NR == 1 {
    sub(/Mounted on/,"Mounted_on")
    while ( match(substr($0,totWid+1),/[^ \t]+[ \t]*/) ) {
        tag = substr($0,totWid+1,RLENGTH)
        sub(/[ \t]+$/,"",tag)
        tags[++numTags] = tag
        begs[numTags] = totWid + 1
        wids[numTags] = RLENGTH
        totWid += RLENGTH
    }
}
{
    for ( i=1; i<=numTags; i++ ) {
        val = substr($0,begs[i],wids[i])
        gsub(/^[ \t]+|[ \t]+$/,"",val)
        f[tags[i]] = val
    }
    print f["Filesystem"], f["Available"], f["Used"]
}

$ awk -f tst.awk file | column -s $'\t' -t
Filesystem             Available  Used
/dev/mapper/xxx_crypt  100G       200G

답변3

사용행복하다(이전 Perl_6)

~$ raku -e 'my $target = "Used"; 
            my @table = lines.map: *.split(/ \h+ /).List; 
            my $col = @table.head.grep(/ $target /, :k).cache; 
            .put for @table.map: *.[ $col.flat ];'   file

위 내용은 Perl 계열의 프로그래밍 언어인 Raku로 작성된 답변입니다. 즉, $-sigiled 스칼라가 선언되고 "Used"라는 문자열이 할당됩니다. 그런 다음 lines읽으면 각 ped가 수평 공백 map으로 들어갑니다 . 일반적으로 이러한 반환은 Raku에서 a라는 경량 데이터 구조에 저장되지만 여기서는 데이터를 배열 에 저장하도록 강제합니다.split\hSeqList@table

이제 올바른 열을 살펴보세요. @table.head테이블의 원래 헤더 행(즉, 행)을 가져옵니다 . grep일치 항목을 찾기 위해 이러한 요소를 살펴본 다음 $target:k인덱스 번호인 키를 가져와서 에 저장합니다 $col. 마지막으로 필요한 열만 반환하여 put데이터를 출력합니다 .@a.table$col

입력 예:

Filesystem                  xxxxxxxxxx-blocks  Used Available Capacity Mounted on
/dev/mapper/xxx_crypt                    500G  200G      100G      xx% /

예제 출력:

Used
200G

OP는 쉘 변수를 허용하는 스크립트에 대한 희망을 표현했습니다. Raku에는 %*ENV쉘 변수에 액세스하는 데 사용할 수 있는 특수 연관 배열이 있습니다 . 따라서 다음은 colName환경(즉, 셸)에서 셸 변수를 가져옵니다.

~$ env colName="Used" raku -e 'my $target = %*ENV<colName>;   \
                      my @table = lines.map: *.split(/ \h+ /).List;     \
                      my $col = @table.head.grep(/$target/, :k).cache;  \
                      .put for @table.map: *.[ $col.flat ];'   file
Used
200G

다음과 같이 약간의 조정을 통해 유사하게 두 개의 열 등을 반환할 수 있습니다.

~$ env colNames="Used Available" raku -e '   \
                      my @target = %*ENV<colNames>.split(/ \h+ /).List;  \
                      my @table = lines.map: *.split(/ \h+ /).List;      \
                      my @col = @table.head.grep(/@target/, :k);         \
                      .put for @table.map: *.[ @col.flat ];'   file
Used Available
200G 100G

https://docs.raku.org/routine/grep
https://raku.org

관련 정보