기간 열을 기준으로 파일을 정렬하는 방법은 무엇입니까?

기간 열을 기준으로 파일을 정렬하는 방법은 무엇입니까?

다음 내용이 포함된 파일을 정렬하려면 어떻게 해야 합니까? (s=초, h=시간, d=일, m=분)

1s
2s
1h
2h
1m
2m
2s
1d
1m

답변1

awk '{ unitvalue=$1; }; 
    /s/ { m=1 }; /m/ { m=60 }; /h/ { m=3600 }; /d/ { m=86400 }; 
    { sub("[smhd]","",unitvalue); unitvalue=unitvalue*m; 
    print unitvalue " " $1; }' input |
        sort -n | awk '{ print $2 }'
1s
2s
2s
1m
1m
2m
1h
2h
1d

답변2

이것은 확장입니다미니맥스의 답변더 넓은 범위의 기간 값을 처리할 수 있습니다 1d3h10m40s.

parse-times.awkGNU Awk 프로그램(이 답변을 위해 저장됨):

#!/usr/bin/gawk -f
BEGIN{
  FPAT = "[0-9]+[dhms]";
  duration["s"] = 1;
  duration["m"] = 60;
  duration["h"] = duration["m"] * 60;
  duration["d"] = duration["h"] * 24;
}

{
  t=0;
  for (i=1; i<=NF; i++)
    t += $i * duration[substr($i, length($i))];
  print(t, $0);
}

옮기다:

gawk -f parse-times.awk input.txt | sort -n -k 1,1 | cut -d ' ' -f 2

다중 열 입력

입력에 여러 열이 포함된 경우 다른 방법을 사용해야 합니다. 다음 코드는 함수를 사용하여 시간 표현식을 구문 분석하고 결과를 새 열로 추가합니다.

#!/usr/bin/gawk -f
# Given a time expression like "1d3h10m40s",  returns its duration in seconds.
# If the expression doesn't match, returns -1.
function parse_time(s) {
    return match(s, /^(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?$/, m) ? m[10] + m[8] * 60 + m[6] * 3600 + m[4] * 86400 + m[2] * 604800 : -1;
}

{
  $(++NF) = parse_time($1);
  print;
}

그런 다음 새 열의 출력을 정렬한 다음 제거할 수 있습니다.

gawk -f parse-times.awk input.txt | sort -n -k 2,2 | cut -d ' ' -f 1

답변3

첫 번째 버전 - FPAT 사용

gawk '
BEGIN {
    FPAT="[0-9]+|[smhd]";
}
/s/ { factor = 1 }
/m/ { factor = 60 }
/h/ { factor = 3600 }
/d/ { factor = 86400 }
{
    print $1 * factor, $0;
}' input.txt | sort -n | awk '{print $2}'

FPAT - 레코드의 필드 내용을 설명하는 정규식입니다. 설정되면 gawk는 입력을 사용하는 대신 필드가 정규식과 일치하는 필드로 입력을 구문 분석합니다.FS변수는 필드 구분 기호 역할을 합니다.

두번째 버전

FPAT없이도 작동한다는 사실에 놀랐습니다 . 이는 디지털 변환 메커니즘으로 인해 발생합니다 awk.awk에서 문자열과 숫자를 변환하는 방법,지금 바로:

문자열의 숫자 접두사를 숫자로 해석하여 문자열을 숫자로 변환합니다. "2.5"는 2.5로 변환되고 "1e3"은 1,000으로 변환되며 "25fix"는 25로 변환됩니다. 유효 숫자가 0으로 변환되므로 해석할 수 없는 문자열입니다.

gawk '
/s/ { factor = 1 }
/m/ { factor = 60 }
/h/ { factor = 3600 }
/d/ { factor = 86400 }
{
    print $0 * factor, $0;
}' input.txt | sort -n | awk '{print $2}'

입력 (약간 변경됨)

1s
122s
1h
2h
1m
2m
2s
1d
1m

산출

노트:122초는 2분 더 길어서 2m 이후로 정렬됩니다.

1s
2s
1m
1m
2m
122s
1h
2h
1d

답변4

Python 3의 솔루션:

#!/usr/bin/python3
import re, fileinput

class RegexMatchIterator:
    def __init__(self, regex, string, error_on_incomplete=False):
        self.regex = regex
        self.string = string
        self.error_on_incomplete = error_on_incomplete
        self.pos = 0

    def __iter__(self):
        return self

    def __next__(self):
        match = self.regex.match(self.string, self.pos)
        if match is not None:
            if match.end() > self.pos:
                self.pos = match.end()
                return match
            else:
                fmt = '{0!s} returns an empty match at position {1:d} for "{3!r}"'

        elif self.error_on_incomplete and self.pos < len(self.string):
            if isinstance(self.error_on_incomplete, str):
                fmt = self.error_on_incomplete
            else:
                fmt = '{0!s} didn\'t match the suffix {3!r} at position {1:d} of {2!r}'

        else:
            raise StopIteration(self.pos)

        raise ValueError(fmt.format(
            self.regex, self.pos, self.string, self.string[self.pos:]))


DURATION_SUFFIXES = { 's': 1, 'm': 60, 'h': 3600, 'd': 24*3600 }
DURATION_PATTERN = re.compile(
    '(\\d+)(' + '|'.join(map(re.escape, DURATION_SUFFIXES.keys())) + ')')

def parse_duration(s):
    return sum(
        int(m.group(1)) * DURATION_SUFFIXES[m.group(2)]
        for m in RegexMatchIterator(DURATION_PATTERN, s,
            'Illegal duration string {3!r} at position {1:d}'))


if __name__ == '__main__':
    with fileinput.input() as f:
        result = sorted((l.rstrip('\n') for l in f), key=parse_duration)
    for item in result:
        print(item)

보시다시피 유용한 반복자를 만드는 데 약 ⅔ 라인이 걸렸습니다.regex.match()결과는 다음과 같습니다.regex.finditer()일치는 현재 범위의 시작 부분에 연결되지 않으며 일치 결과를 반복하는 다른 적절한 방법은 없습니다.*굴루*

관련 정보