레코드 내의 날짜/시간 위치가 다를 수 있는 레코드의 날짜/시간 부분을 기준으로 목록을 정렬합니다.

레코드 내의 날짜/시간 위치가 다를 수 있는 레코드의 날짜/시간 부분을 기준으로 목록을 정렬합니다.

이름의 날짜/시간 부분을 기준으로 목록을 정렬하고 싶습니다.

정렬을 사용할 수 있나요? 아래 입력 예와 같이 열이 달라질 수 있으므로 정렬 열을 지정할 수 없습니다.

swid_ds_install_user_20171227172654_20425.log
package_user_20171227172949_5627.log
swid_state_definition_user_20171227162839_6515.log
swid_ds_install_user_20171227172732_23839.log
swid_appsrv_stop_user_20171227172258_27116.log
package_user_20171227172610_16198.log
swid_state_definition_user_20171227172344_322.log
package_user_20171227233634_23845.log
package_user_20171227162858_7082.log

예를 들어 필드의 순서를 바꿀 수 있습니다.

awk -F_ '{for (i=NF;i>0;i--){printf $i"_"};printf "\n"}'

그런 다음 -d_ -k2,2로 정렬한 다음 원래 파일 이름을 유지하기 위해 필드 순서를 반대로 바꿉니다. 예를 들어 sed를 사용하여 잔여 구분 기호를 제거합니다. 하지만 이는 어색해집니다.

awk -F_ '{for (i=NF;i>0;i--){printf $i"_"};printf "\n"}' | sort -t'_' -k2,2 \
| awk -F_ '{for (i=NF;i>0;i--){printf $i"_"};printf "\n"}' | sed 's/^_//' \ 
| sed 's/_$//'

이 문제를 어떻게 처리하시겠습니까?

sed를 사용하여 정규식을 통해 날짜/시간 부분을 분리하고 정렬한 다음 출력을 인쇄할 때 일치하는 정규식뿐만 아니라 전체 파일 이름을 복구하기 위해 일부 내장 기능을 사용할 생각입니다.

또 다른 복제본을 만들지 않았기를 바랍니다. 문제 설명을 실제로 요약할 수는 없습니다.

답변1

awk -F_ '{print $(NF-1), $0}' | sort -k1,1 -n | cut -d' ' -f2-

이는 필드 구분 기호로 awkwith를 사용하여 _두 번째 필드를 마지막 필드(날짜 시간)를 줄의 시작 부분에 추가한 다음 sort해당 필드의 입력만 숫자로 정렬한 다음 cut추가 필드를 제거하는 데 사용됩니다.

예제 출력은 예제 입력을 다음 이름의 파일에 저장합니다 file.

$ awk -F_ '{print $(NF-1), $0}' file  | sort -k1,1 -n | cut -d' ' -f2-
swid_state_definition_user_20171227162839_6515.log
package_user_20171227162858_7082.log
swid_appsrv_stop_user_20171227172258_27116.log
swid_state_definition_user_20171227172344_322.log
package_user_20171227172610_16198.log
swid_ds_install_user_20171227172654_20425.log
swid_ds_install_user_20171227172732_23839.log
package_user_20171227172949_5627.log
package_user_20171227233634_23845.log

이는 날짜/시간이 항상 두 번째에서 마지막 필드에 있다고 가정합니다. 그렇다면아니요이 경우 GNU awk를 사용하면 다음 패턴을 캡처할 수 있습니다.것 같다날짜/시간처럼 줄 시작 부분에 추가하세요.

$ awk -F_ '{match($0,"_(20[0-9]{12})_",dt); print dt[1], $0}' file |
    sort -k1,1 -n | cut -d' ' -f2-

하지만 저는 perl이런 경우에 사용하는 편입니다.

GNU awk의 match()함수는 선택적인 세 번째 인수, 즉 캡처된 일치 항목을 저장하는 데 사용되는 배열 변수의 이름을 사용합니다. 이 경우 캡처는 하나만 있으므로 배열의 첫 번째 요소에 저장됩니다(예: ) dt[1]. IIRC, POSIX awk에는 여전히 정규식 일치 항목을 잡을 수 있는 방법이 없습니다.

그런데, 이제 가정은 연도 >= 2000입니다. 입력 데이터가 항상 그렇지 않은 경우 정규식을 적절하게 조정하십시오.

답변2

예를 들어, 여기에서 glob을 사용할 수 있습니다 zsh.

printf '%s\n' *_user_*.log(oe:'REPLY=${REPLY##*user_}':)

여기서는 oe:...:주어진 표현식을 기반으로 정렬 순서를 정의합니다. 여기서는 "user_" 오른쪽에 있는 파일 이름 부분을 선택합니다.

마지막 2개를 정렬하세요 _*.

printf '%s\n' *_*_*.log(oe:'REPLY=${(M)REPLY%_*_*}':)

답변3

다음과 같이 작동할 것 같습니다.

$ perl -e 'sub key($) { $_[0] =~ /(\d+)_\d+\.log$/; return $1; }; 
     @lines = <>; print sort {key($a) cmp key($b)}  @lines;'  < files
swid_state_definition_user_20171227162839_6515.log
package_user_20171227162858_7082.log
swid_appsrv_stop_user_20171227172258_27116.log
swid_state_definition_user_20171227172344_322.log
package_user_20171227172610_16198.log
swid_ds_install_user_20171227172654_20425.log
swid_ds_install_user_20171227172732_23839.log
package_user_20171227172949_5627.log
package_user_20171227233634_23845.log

이 서브루틴은 key날짜/시간이 항상 파일 이름의 끝에서 두 번째 부분, .log기타 숫자 필드 앞에 있는 것으로 보인다는 사실을 기반으로 숫자 문자열을 선택합니다. 그런 다음 입력 줄을 읽고 출력을 정렬 키로 사용하여 key()정렬하여 인쇄합니다 .

Perl은 인라인 코드 블록을 사용하여 sort비교할 값을 얻고 보다 작거나 같거나 크거나(문자열로 비교) 반환할 수 있습니다.$a$bcmp

타임스탬프의 위치가 실제로 더 다를 수 있는 경우 sub를 변경하여 문자열의 어느 곳에서나 밑줄로 구분된 14자리 문자열을 선택할 수 있습니다.

sub key($) { $_[0] =~ /_(\d{14})_/; return $1; }

관련 정보