다음 데이터 구조를 포함하는 CSV가 있습니다.
1111,2222,3333,4444,5555,6666,7777,2017-1-5 1:07:09,2017-1-5 1:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
날짜, 월, 일을 항상 2자리로 표시하고 싶습니다. 또한 시간 필드가 항상 2자리가 되기를 원합니다.
월/일/시간 필드가 단일 숫자인 경우(위의 예시 행에서처럼) 본질적으로 앞에 0을 추가하는 것입니다.
awk를 사용하면 어떻게 다음 결과를 얻을 수 있습니까?
1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
답변1
훌륭한 텍스트 처리 도구는 다음과 같습니다.앗. 다음 예에서는 FreeBSD 11.1에서 일반 표준 awk를 사용합니다. GNU awk를 선호한다면 @RomanPerekhrest는 또 다른 답변에 우아한 솔루션을 제공합니다.
입력 내용은 쉼표로 구분됩니다. 따라서 awk
매개변수를 사용하여 호출합니다 -F,
.
그런 다음 이 명령문을 사용하여 열을 인쇄할 수 있습니다 print
. $1
첫 번째 열입니다. $2
두 번째 칼럼입니다.
$ awk -F, '{ print $8 }' inputfile.csv
2017-1-5 1:07:09
2017-11-25 19:57:17
이는 각 행의 8번째 열을 제공합니다.
이는 작업하려는 날짜 필드입니다. 구분 기호를 설정하기 위해 명령줄 인수를 사용하는 대신 이를 스크립트의 일부로 설정할 수 있습니다. FS는 입력 구분 기호로 사용되고 OFS는 출력 구분 기호로 사용됩니다.
$ awk 'BEGIN { FS = "," } ; { print $8 }' inputfile.csv
2017-1-5 1:07:09
2017-11-25 19:57:17
날짜를 다룰 때 나는 일반적으로 date
날짜가 올바르게 처리되는지 확인하기 위해 util을 사용하는 것을 선호합니다. 일반 또는 GNU awk를 사용하는지 걱정할 필요가 없습니다. 또한 날짜를 잘못 구문 분석하면 큰 실패가 발생합니다.
흥미로운 매개변수는 다음과 같습니다.
-j Specify we do not want to set the date at all
-f The format string we use for input
+ The format string we use for output
따라서 이 날짜를 실행하면 다음과 같습니다.
$ date -j -f "%Y-%m-%d %H:%M:%S" +"%Y-%m-%d %H:%M:%S" "2017-1-5 1:07:09"
2017-01-05 01:07:09
그런 다음 이것을 awk와 결합할 수 있습니다. 따옴표가 어떻게 생겼는지 확인하세요.탈출하다. 초보자에게는 이것이 가장 큰 걸림돌이 될 수 있습니다.
$ awk -F, '{ system("date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$8"\"")}' inputfile.csv
2017-01-05 01:07:09
2017-11-25 19:57:17
시스템 호출은 올바른 것 같지만 불행하게도 반환 코드를 캡처하여 출력에 직접 인쇄할 수만 있습니다. 이를 방지하기 위해 이 패턴을 사용합니다 cmd | getline
. 다음의 간단한 예에서는 현재 날짜를 mydate로 읽습니다.
$ awk 'BEGIN { cmd = "date"; cmd | getline mydate; close(cmd); print mydate }'
Thu Mar 1 16:26:15 CET 2018
BEGIN
이 간단한 예에서는 입력이 없기 때문에 키워드를 사용합니다 .
이제 조금 확장해 보겠습니다.
awk 'BEGIN { FS=","; OFS=FS };
{
cmd = "date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$8"\"";
cmd | getline firstdate;
close(cmd);
cmd = "date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$9"\"";
cmd | getline seconddate;
close(cmd);
print $1,$2,$3,$4,$5,$6,$7,firstdate,seconddate
}' inputfile.csv
한 줄로 축소할 수 있습니다.
awk 'BEGIN {FS=",";OFS=FS};{cmd="date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$8"\"";cmd | getline firstdate;close(cmd);cmd="date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$9"\"";cmd | getline seconddate;close(cmd);print $1,$2,$3,$4,$5,$6,$7,firstdate,seconddate}' inputfile.csv
결과는 다음과 같습니다.
1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
부록
여기서의 목적은 좋은 습관을 배우는 것이므로 이 답변을 업데이트하는 것이 좋습니다. 코드를 복제하는 것은 나쁜 습관입니다. 이 작업을 시작하면 모든 것을 함수로 나누어야 합니다. 아래 코드가 즉시 더 읽기 쉬워지는 것을 확인할 수 있습니다.
awk 'function convertdate(the_date) {
cmd = "date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""the_date"\"";
cmd | getline formatted_date;
close(cmd);
return formatted_date
}
BEGIN { FS=","; OFS=FS };
{
print $1,$2,$3,$4,$5,$6,$7,convertdate($8),convertdate($9)
}' inputfile.csv
습관을 들이면 나중에 오류 처리를 도입하는 것이 얼마나 쉬운지 알게 될 것입니다.
답변2
GNU awk가 있으면 마지막 필드를 공백으로 구분된 필드로 변환할 수 있습니다.날짜 사양문자열을 입력한 다음 필요에 따라 다음을 사용하여 형식을 다시 지정합니다 strftime
.
awk 'BEGIN{OFS=FS=","} {gsub(/[-:]/," ",$NF); $NF = strftime("%Y-%m-%d %H:%M:%S", mktime($NF))} 1' file
1111,2222,3333,4444,5555,6666,7777,2017-1-5 1:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
답변3
간단한 GNUawk
해결책:
awk 'BEGIN{ FS=OFS="," }{ gsub(/\<[0-9]\>/, "0&", $8); gsub(/\<[0-9]\>/, "0&", $9) }1' file
gsub(/\<[0-9]\>/, "0&", <field>)
- 개별 한 자리 숫자만 대체/보충날짜 시간끈:\<
및\>
- 단어 경계입니다.&
- 정규식 패턴 일치의 정확한 하위 문자열을 나타냅니다.
산출:
1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
답변4
이것날짜 도구패키지에는 시간/날짜 형식 데이터의 세부 정보를 처리하는 코드가 있습니다.
# Utility functions: print-as-echo, print-line-with-visual-space.
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }
pl " Input data file $FILE:"
head $FILE
pl " Expected output:"
cat $E
pl " Results, to standard format:"
dateutils.dconv -S <$FILE
pl " Results, to standard format, omitting the \"T\":"
dateutils.dconv -S -f '%F %T' <$FILE
생산:
-----
Input data file data1:
1111,2222,3333,4444,5555,6666,7777,2017-1-5 1:07:09,2017-1-5 1:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
-----
Expected output:
1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
-----
Results, to standard format:
1111,2222,3333,4444,5555,6666,7777,2017-01-05T01:07:09,2017-01-05T01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25T19:57:17,2017-11-25T19:58:54
-----
Results, to standard format, omitting the "T":
1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54
이러한 시스템에서는:
OS, ker|rel, machine: Linux, 3.16.0-4-amd64, x86_64
Distribution : Debian 8.9 (jessie)
bash GNU bash 4.3.30
dateutils.dconv dconv 0.3.1
dconv에 대한 세부 정보:
dateutils.dconv Convert DATE/TIMEs between calendrical systems. (man)
Path : /usr/bin/dateutils.dconv
Package : dateutils
Home : http://www.fresse.org/dateutils
Version : 0.3.1
Type : ELF 64-bit LSB shared object, x86-64, version 1 ( ...)
Help : probably available with -h,--help
Home : https://github.com/hroptatyr/dateutils (doc)
행운을 빕니다... 건배, drl