행 중앙에 위치한 키워드 뒤의 해당 행에서 값만 가져옵니다.

행 중앙에 위치한 키워드 뒤의 해당 행에서 값만 가져옵니다.

안녕하세요, 파일 중간에 다음 줄이 있는데 "energy=" 뒤에 있는 값을 가져와야 합니다. 줄 번호는 "lineNumber"라는 변수에 저장됩니다. 파일에 구조는 동일하지만 값이 다른 다른 줄이 있습니다. 나는 "lineNumber"에 정의된 라인의 에너지 값만 원합니다. 도움을 주셔서 감사합니다. 감사합니다!

Properties=species:S:1:pos:R:3:velocities:R:3:forces:R:3:local_energy:R:1:fix_atoms:S:3 Lattice="42.0000000000       0.0000000000    0.0000000000    0.0000000000   46.0000000000    0.0000000000    0.0000000000    0.0000000000   50.0000000000" temperature=327.11679001 pressure=14.24003276 time_step=5.0000 time=5000.0000 energy=-18.022194 virial="0.46990039            0.48760331     -0.77576961      0.48760331      0.78141847      0.59471844     -0.77576961      0.59471844      0.64787347" stress="-0.00000486          -0.00000505      0.00000803     -0.00000505     -0.00000809     -0.00000616      0.00000803     -0.00000616     -0.00000671" volume=96600.000000 step=1000

답변1

Linux 기반 시스템을 사용하고 있으므로 GNU를 사용하고 있는 것이 거의 확실합니다.grep

grep -oP 'energy=\K[^\s]+'

예를 들어

echo 'Properties=species:S:1:pos:R:3:velocities:R:3:forces:R:3:local_energy:R:1:fix_atoms:S:3 Lattice="…" temperature=327.11679001 … time=5000.0000 energy=-18.022194 virial="0.46990039 …" stress="…" volume=96600.000000 step=1000' |
    grep -oP 'energy=\K[^\s]+'

산출

-18.022194

당신은 다음과 같은 것을 사용할 수 있습니다sed

lineNumber=123
sed -n "${lineNumber}{p;q}" file

이것들을 종합하면,

sed -n "${lineNumber}{p;q}" file | grep -oP 'energy=\K[^\s]+'

다음과 같은 것을 사용할 수도 있습니다 perl.

perl -e '
    $lineNumber = shift;                                 # Arg 1 is line number
    $fieldName = shift;                                  # Arg 2 is field name
    while (defined($line = <>)) {                        # Read lines from file or stdin
        next unless $. == $lineNumber;                   # Skip until required line
        chomp $line;                                     # Discard newline
        %a =                                             # Create key/value array. Read the next lines upwards
            map { split(/=/, $_, 2) }                    # 3. Split into {key,value} tuples
            grep { /=/ }                                 # 2. Only interested in assignments
            split(/(\w+=(".*?"|[^"].*?)\s+)/, $line);    # 1. Split line into « key=value » and « key="several values" » fields
        print $a{$fieldName}, "\n";                      # Print chosen field value
        exit 0
    }
' "$lineNumber" 'energy' file

답변2

awk -v lineNumber="$lineNumber" -v FS="energy=" 'NR == lineNumber {print $2}' FILE | awk '{print $1}'

답변3

현재 요구 사항에 비해 약간 과잉일 수 있지만 레이블-값 매핑 배열을 만들 수 있습니다(아래 배열에 저장됨 f[]).

$ awk -v FPAT='[^=[:space:]]+=([^[:space:]]+|"[^"]*")' -v n="$lineNumber" '
    NR == n {
        delete f
        for (i=1; i<=NF; i++) {
            f[gensub(/=.*/,"",1,$i)] = gensub(/[^=]+=/,"",1,$i)
        }
        print f["energy"]
    }
' file
-18.022194

f[]그런 다음 레이블(이름)을 사용하여 색인을 생성하여 값 또는 값 조합에 대해 원하는 작업을 수행할 수 있습니다. 예를 들어 다음과 같이 작성할 수 있습니다.

awk -v FPAT='[^=[:space:]]+=([^[:space:]]+|"[^"]*")' '
    {
        delete f
        for (i=1; i<=NF; i++) {
            f[gensub(/=.*/,"",1,$i)] = gensub(/[^=]+=/,"",1,$i)
        }
    }
    (f["time"] < 6) && (f["volume"] > 8) {
        print f["temperature"], f["energy"], f["step"] / f["time_step"]
    }
' file
327.11679001 -18.022194 200

또는 비교/계산/인쇄해야 할 다른 모든 것.

위의 내용은 GNU awk를 사용하여 FPATsum 을 처리합니다 . 코드만 조금 더 추가하면 gensub()지원되는 POSIX awk를 사용하여 대부분(모두는 아니지만)과 동일한 작업을 수행할 수 있습니다 .delete array

$ awk -v n="$lineNumber" '
    NR == n {
        delete f
        rec = $0
        while ( match(rec,/[^=[:space:]]+=([^[:space:]]+|"[^"]*")/) ) {
            tag = val = substr(rec,RSTART,RLENGTH)
            sub(/=.*/,"",tag)
            sub(/[^=]+=/,"",val)
            f[tag] = val
            rec = substr(rec,RSTART+RLENGTH)
        }
        print f["energy"]
    }
' file
-18.022194

awk가 불만을 표시하면 해당 줄을 어떤 awk에서도 작동하는 delete f줄로 변경하세요 .split("",f)

답변4

사용행복하다(이전 Perl_6)

~$ raku -ne 'put ++$ => $/ if ++$ == 1 && m/ \s energy\= <( <+ :N + [\-+.]>+  )> \s /;'   file

또는:

~$ raku -ne 'put ++$ => $0 if ++$ == 1 && m/ \s energy\=  ( <+ :N + [\-+.]>+  )  \s /;'    file

또는:

~$ raku -ne 'put ++$ => $<val> if ++$ == 1 && m/ \s energy\=  $<val>=<+ :N + [\-+.]>+   \s /;'   file

위의 Raku 코드는 -ne자동 인쇄가 아닌 라인별 플래그를 사용합니다(코드는 입력 파일에서 라인별로 실행됩니다). 오른쪽에서 왼쪽으로 읽으면서 m/.../다음 필수 값과 일치하는 항목을 찾습니다 energy=. 이 일치 항목은 유니코드 숫자와 문자 , , 가 한 번 이상 나타나는 <+ :N + [\-+.]>+복합 문자 클래스 인 Raku Regex 방언으로 작성되었습니다 ( 이 구조에서 백슬래시 이스케이프가 필요한 몇 안 되는 문자 중 하나). 이 문자 클래스를 작성할 수 있지만 유니코드 이외의 숫자와의 일치는 손실됩니다 .:N-+.-<+[0..9\-+.]>+0..9

++$Raku에서 줄 번호를 계산하는 가장 간단한 방법은 1부터 시작하는 자동 증가 카운터를 실행하는 것입니다 . 이를 하나로 합치면(이제 왼쪽에서 오른쪽으로 읽음) 첫 번째 예제 코드는 다음과 같습니다."줄 번호가 수치적으로 1과 같고 줄 번호 put뒤에 ++$내장 $/일치 변수가 오면 필요한 일치 항목이 발견되고 캡처 태그를 제외한 모든 항목이 제거됩니다."if ++$ == 1&&<( ... )>. 부울은 &&사용되기 때문에 단락됩니다. ( ++$ =>반환하려는 것이 값뿐이라면 출력에서 ​​해당 값을 제거하십시오.)

샘플 입력(OP의 데이터는 3회 사용됨):

Properties=species:S:1:pos:R:3:velocities:R:3:forces:R:3:local_energy:R:1:fix_atoms:S:3 Lattice="42.0000000000       0.0000000000    0.0000000000    0.0000000000   46.0000000000    0.0000000000    0.0000000000    0.0000000000   50.0000000000" temperature=327.11679001 pressure=14.24003276 time_step=5.0000 time=5000.0000 energy=-18.022194 virial="0.46990039            0.48760331     -0.77576961      0.48760331      0.78141847      0.59471844     -0.77576961      0.59471844      0.64787347" stress="-0.00000486          -0.00000505      0.00000803     -0.00000505     -0.00000809     -0.00000616      0.00000803     -0.00000616     -0.00000671" volume=96600.000000 step=1000
Properties=species:S:1:pos:R:3:velocities:R:3:forces:R:3:local_energy:R:1:fix_atoms:S:3 Lattice="42.0000000000       0.0000000000    0.0000000000    0.0000000000   46.0000000000    0.0000000000    0.0000000000    0.0000000000   50.0000000000" temperature=327.11679001 pressure=14.24003276 time_step=5.0000 time=5000.0000 energy=-18.022194 virial="0.46990039            0.48760331     -0.77576961      0.48760331      0.78141847      0.59471844     -0.77576961      0.59471844      0.64787347" stress="-0.00000486          -0.00000505      0.00000803     -0.00000505     -0.00000809     -0.00000616      0.00000803     -0.00000616     -0.00000671" volume=96600.000000 step=1000
Properties=species:S:1:pos:R:3:velocities:R:3:forces:R:3:local_energy:R:1:fix_atoms:S:3 Lattice="42.0000000000       0.0000000000    0.0000000000    0.0000000000   46.0000000000    0.0000000000    0.0000000000    0.0000000000   50.0000000000" temperature=327.11679001 pressure=14.24003276 time_step=5.0000 time=5000.0000 energy=-18.022194 virial="0.46990039            0.48760331     -0.77576961      0.48760331      0.78141847      0.59471844     -0.77576961      0.59471844      0.64787347" stress="-0.00000486          -0.00000505      0.00000803     -0.00000505     -0.00000809     -0.00000616      0.00000803     -0.00000616     -0.00000671" volume=96600.000000 step=1000

출력 예(탭으로 구분된 반환):

1   -18.022194

lineNumber마지막으로, 한 줄에 하드코딩하는 대신 명령줄에서 입력하고 싶다면 envRaku는 내부적으로 환경 변수를 동적 해시 변수로 사용할 수 있습니다 %*ENV. 따라서 다음을 수행할 수 있습니다(첫 번째 문자 env는 선택 사항임).

~$ env lineNumber="1" perl6 -ne 'put $0 if ++$ == %*ENV<lineNumber> && m/ \s energy\=  ( <+[0..9\-+.]>+ )  \s /;'   file
-18.022194

https://docs.raku.org/언어/regexes
https://raku.org

관련 정보